X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=da38843b74e210b56f9694fe644fbc2fed360ed1;hb=b8f207892a11b53365c47b4828254269fca5c8e9;hp=e7711692995df6d25dc27c00b938bcc041c62824;hpb=ec21f8c9ec160466ba0a1aa662da8af5cb6a3c9b;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index e7711692..da38843b 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -314,7 +314,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); @@ -407,9 +408,9 @@ void client_manage(Window window) do this after adjusting the frame. otherwise it gets all weird and clients don't work right */ - client_configure_full(self, self->area.x, self->area.y, - self->area.width, self->area.height, - FALSE, TRUE); + client_configure(self, self->area.x, self->area.y, + 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!! @@ -506,6 +507,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 +531,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 +539,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 +573,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); @@ -694,30 +702,39 @@ 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; + if (app->class && + !g_pattern_match(app->class, strlen(self->class),self->class,NULL)) + match = FALSE; + 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); } } @@ -853,9 +870,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); @@ -1585,7 +1604,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)) @@ -1684,6 +1704,11 @@ void client_setup_decor_and_functions(ObClient *self) if (self->max_vert && self->max_horz) 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) { @@ -1715,7 +1740,7 @@ void client_setup_decor_and_functions(ObClient *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 +1767,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); @@ -2337,18 +2364,16 @@ static ObStackingLayer calc_layer(ObClient *self) else l = OB_STACKING_LAYER_ABOVE; } else if ((self->fullscreen || - /* no decorations and fills the monitor = oldskool fullscreen */ - (self->frame != NULL && - (self->frame->size.right == 0 && self->frame->size.left == 0 && - self->frame->size.bottom == 0 && self->frame->size.top == 0 && - RECT_EQUAL(self->area, - *screen_physical_area_monitor - (client_monitor(self))))))) { - if (client_focused(self) || client_search_focus_tree(self)) - l = OB_STACKING_LAYER_FULLSCREEN; - else - l = OB_STACKING_LAYER_FULLSCREEN_BELOW; - } + /* No decorations and fills the monitor = oldskool fullscreen. + But not for undecorated windows, because the user can do that + */ + (self->decorations == 0 && + !self->undecorated && + RECT_EQUAL(self->area, + *screen_physical_area_monitor + (client_monitor(self))))) && + (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; @@ -2402,11 +2427,13 @@ gboolean client_should_show(ObClient *self) return FALSE; } -void client_show(ObClient *self) +gboolean client_show(ObClient *self) { + gboolean show = FALSE; 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 @@ -2414,27 +2441,42 @@ void client_show(ObClient *self) desktop! */ client_change_wm_state(self); + return show; } -void client_hide(ObClient *self) +gboolean client_hide(ObClient *self) { - if (!client_should_show(self)) + gboolean hide = FALSE; + + if (!client_should_show(self)) { + if (self == focus_client) { + /* 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 ! + + actions should not rely on being able to move focus during an + interactive grab. + */ + if (keyboard_interactively_grabbed()) + keyboard_interactive_cancel(); + } + 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); + return hide; } void client_showhide(ObClient *self) { - - if (client_should_show(self)) - frame_show(self->frame); - else - frame_hide(self->frame); + 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 @@ -2689,14 +2731,16 @@ 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) +void client_configure(ObClient *self, gint x, gint y, gint w, gint h, + gboolean user, gboolean final) { gint oldw, oldh; gboolean send_resize_client; gboolean moved = FALSE, resized = FALSE; + 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) */ @@ -2730,10 +2774,15 @@ void client_configure_full(ObClient *self, gint x, gint y, gint w, gint h, } /* find the frame's dimensions and move/resize it */ - if (self->decorations != fdecor || self->max_horz != fhorz) - moved = resized = TRUE; - if (moved || resized) - frame_adjust_area(self->frame, moved, resized, FALSE); + fmoved = moved; + fresized = resized; + if (self->decorations != fdecor || + self->max_horz != fhorz || self->max_vert != fvert) + { + fmoved = fresized = TRUE; + } + if (fmoved || fresized) + frame_adjust_area(self->frame, fmoved, fresized, FALSE); if ((!user || (user && final)) && !resized) { @@ -3253,6 +3302,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) } } } + if (max_horz != self->max_horz || max_vert != self->max_vert) { if (max_horz != self->max_horz && max_vert != self->max_vert) { /* toggling both */ @@ -3278,24 +3328,30 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) client_shade(self, shaded); if (undecorated != self->undecorated) client_set_undecorated(self, undecorated); + if (above != self->above || below != self->below) { + self->above = above; + self->below = below; + client_calc_layer(self); + } + if (modal != self->modal) { self->modal = modal; /* when a window changes modality, then its stacking order with its transients needs to change */ stacking_raise(CLIENT_AS_WINDOW(self)); + + /* it also may get focused. if something is focused that shouldn't + be focused anymore, then move the focus */ + if (focus_client && client_focus_target(focus_client) != focus_client) + client_focus(focus_client); } + if (iconic != self->iconic) client_iconify(self, iconic, FALSE, FALSE); if (demands_attention != self->demands_attention) client_hilite(self, demands_attention); - if (above != self->above || below != self->below) { - self->above = above; - self->below = below; - client_calc_layer(self); - } - client_change_state(self); /* change the hint to reflect these changes */ } @@ -3324,8 +3380,6 @@ gboolean client_can_focus(ObClient *self) gboolean client_focus(ObClient *self) { - gboolean error; - /* choose the correct target */ self = client_focus_target(self); @@ -3351,8 +3405,8 @@ gboolean client_focus(ObClient *self) if (keyboard_interactively_grabbed()) keyboard_interactive_cancel(); - error = FALSE; xerror_set_ignore(TRUE); + xerror_occured = FALSE; if (self->can_focus) { /* This can cause a BadMatch error with CurrentTime, or if an app @@ -3376,13 +3430,9 @@ gboolean client_focus(ObClient *self) XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce); } - /* This calls XSync, which will cause the FocusIn to come back to us. - That's important for desktop switches, since otherwise we'll have no - FocusIn on the queue and end up falling back again. */ xerror_set_ignore(FALSE); - if (!xerror_occured) error = TRUE; - return !error; + return !xerror_occured; } /*! Present the client to the user. @@ -3442,12 +3492,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); } @@ -3552,16 +3599,13 @@ 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); - /* Make sure the client knows it might have moved. Maybe there is a - * better way of doing this so only one client_configure is sent, but - * since 125 of these are sent per second when moving the window (with - * user = FALSE) i doubt it matters much. - */ - client_configure(self, self->area.x, self->area.y, - self->area.width, self->area.height, TRUE, TRUE); client_change_state(self); /* reflect this in the state hints */ } }