X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=e77a4ea6f9e141eb6d5acf61c71f45fea503b35b;hb=209d8df0b15702b523862f1717e055350a34c812;hp=47f807d80adad7efe160cbbe886f01cab1e418b9;hpb=0ee1581824f4693884a6f0abde62d20642df82ed;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index 47f807d8..e77a4ea6 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -65,7 +65,6 @@ typedef struct GList *client_list = NULL; static GSList *client_destroy_notifies = 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); @@ -139,29 +138,6 @@ void client_remove_destroy_notify(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_hide_notifies, 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; @@ -386,6 +362,12 @@ void client_manage(Window window) if (ob_state() == OB_STATE_RUNNING) { gboolean transient; + ob_debug("Positioned: %s @ %d %d\n", + (!self->positioned ? "no" : + (self->positioned == PPosition ? "program specified" : + (self->positioned == USPosition ? "user specified" : + "BADNESS !?"))), self->area.x, self->area.y); + transient = place_client(self, &self->area.x, &self->area.y, settings); /* make sure the window is visible. */ @@ -408,10 +390,6 @@ void client_manage(Window window) !self->session)); } - /* 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 - */ ob_debug("placing window 0x%x at %d, %d with size %d x %d\n", self->window, self->area.x, self->area.y, self->area.width, self->area.height); @@ -419,14 +397,25 @@ void client_manage(Window window) ob_debug(" but session requested %d %d instead, overriding\n", self->session->x, self->session->y); - /* generate a ConfigureNotify telling the client where it is */ - client_configure_full(self, self->area.x, self->area.y, - self->area.width, self->area.height, - FALSE, TRUE); + /* 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); - client_apply_startup_state(self); - mouse_grab_for_client(self, TRUE); + /* 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, + 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 ? @@ -494,9 +483,7 @@ 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); - frame_adjust_client_area(self->frame); + mouse_grab_for_client(self, TRUE); /* 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 @@ -519,7 +506,8 @@ void client_manage(Window window) /* update the list hints */ client_set_list(); - ob_debug("Managed window 0x%lx (%s)\n", window, self->class); + ob_debug("Managed window 0x%lx plate 0x%x (%s)\n", + window, self->frame->plate, self->class); return; } @@ -561,7 +549,8 @@ void client_unmanage(ObClient *self) guint j; GSList *it; - ob_debug("Unmanaging window: %lx (%s) (%s)\n", self->window, + ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n", + self->window, self->frame->plate, self->class, self->title ? self->title : ""); g_assert(self != NULL); @@ -576,7 +565,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); @@ -864,9 +853,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); @@ -1175,7 +1166,7 @@ static void client_get_state(ObClient *self) self->below = TRUE; else if (state[i] == prop_atoms.net_wm_state_demands_attention) self->demands_attention = TRUE; - else if (state[i] == prop_atoms.openbox_wm_state_undecorated) + else if (state[i] == prop_atoms.ob_wm_state_undecorated) self->undecorated = TRUE; } @@ -1594,7 +1585,10 @@ void client_setup_decor_and_functions(ObClient *self) OB_CLIENT_FUNC_ICONIFY | OB_CLIENT_FUNC_MAXIMIZE | OB_CLIENT_FUNC_SHADE | - OB_CLIENT_FUNC_CLOSE); + OB_CLIENT_FUNC_CLOSE | + OB_CLIENT_FUNC_BELOW | + 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)) @@ -1626,10 +1620,15 @@ void client_setup_decor_and_functions(ObClient *self) self->functions = OB_CLIENT_FUNC_MOVE; case OB_CLIENT_TYPE_DESKTOP: - case OB_CLIENT_TYPE_DOCK: /* these windows are not manipulated by the window manager */ self->decorations = 0; self->functions = 0; + + case OB_CLIENT_TYPE_DOCK: + /* these windows are not manipulated by the window manager, but they + can set below layer which has a special meaning */ + self->decorations = 0; + self->functions = OB_CLIENT_FUNC_BELOW; break; } @@ -1688,6 +1687,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) { @@ -1719,7 +1723,7 @@ void client_setup_decor_and_functions(ObClient *self) static void client_change_allowed_actions(ObClient *self) { - gulong actions[9]; + gulong actions[12]; gint num = 0; /* desktop windows are kept on all desktops */ @@ -1742,6 +1746,12 @@ static void client_change_allowed_actions(ObClient *self) actions[num++] = prop_atoms.net_wm_action_maximize_horz; actions[num++] = prop_atoms.net_wm_action_maximize_vert; } + if (self->functions & OB_CLIENT_FUNC_ABOVE) + 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); @@ -2279,7 +2289,7 @@ static void client_change_state(ObClient *self) if (self->demands_attention) netstate[num++] = prop_atoms.net_wm_state_demands_attention; if (self->undecorated) - netstate[num++] = prop_atoms.openbox_wm_state_undecorated; + netstate[num++] = prop_atoms.ob_wm_state_undecorated; PROP_SETA32(self->window, net_wm_state, atom, netstate, num); if (self->frame) @@ -2337,13 +2347,14 @@ 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)))))) && + /* 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; @@ -2399,11 +2410,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 @@ -2411,14 +2424,28 @@ void client_show(ObClient *self) desktop! */ client_change_wm_state(self); + return show; } -void client_hide(ObClient *self) +gboolean client_hide(ObClient *self) { + gboolean hide = FALSE; + if (!client_should_show(self)) { - frame_hide(self->frame); + 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 ! - client_call_notifies(self, client_hide_notifies); + 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 @@ -2426,19 +2453,13 @@ void client_hide(ObClient *self) 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); - - client_call_notifies(self, client_hide_notifies); - } + 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 @@ -2693,12 +2714,13 @@ 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; gint logicalw, logicalh; @@ -2734,10 +2756,12 @@ void client_configure_full(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) - moved = resized = TRUE; - if (moved || resized) - frame_adjust_area(self->frame, moved, resized, FALSE); + fmoved = fresized = TRUE; + if (fmoved || fresized) + frame_adjust_area(self->frame, fmoved, fresized, FALSE); if ((!user || (user && final)) && !resized) { @@ -2790,7 +2814,6 @@ void client_fullscreen(ObClient *self, gboolean fs) self->fullscreen = fs; client_change_state(self); /* change the state hints on the client */ - client_calc_layer(self); /* and adjust out layer/stacking */ if (fs) { self->pre_fullscreen_area = self->area; @@ -2805,36 +2828,36 @@ void client_fullscreen(ObClient *self, gboolean fs) self->pre_fullscreen_area.height = self->pre_max_area.height; } - /* these are not actually used cuz client_configure will set them - as appropriate when the window is fullscreened */ - x = y = w = h = 0; + /* these will help configure_full figure out where to fullscreen + the window */ + x = self->area.x; + y = self->area.y; + w = self->area.width; + h = self->area.height; } else { - Rect *a; + g_assert(self->pre_fullscreen_area.width > 0 && + self->pre_fullscreen_area.height > 0); - if (self->pre_fullscreen_area.width > 0 && - self->pre_fullscreen_area.height > 0) - { - x = self->pre_fullscreen_area.x; - y = self->pre_fullscreen_area.y; - w = self->pre_fullscreen_area.width; - h = self->pre_fullscreen_area.height; - RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0); - } else { - /* pick some fallbacks... */ - a = screen_area_monitor(self->desktop, 0); - x = a->x + a->width / 4; - y = a->y + a->height / 4; - w = a->width / 2; - h = a->height / 2; - } + x = self->pre_fullscreen_area.x; + y = self->pre_fullscreen_area.y; + w = self->pre_fullscreen_area.width; + h = self->pre_fullscreen_area.height; + RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0); } client_setup_decor_and_functions(self); client_move_resize(self, x, y, w, h); - /* try focus us when we go into fullscreen mode */ - client_focus(self); + /* and adjust our layer/stacking. do this after resizing the window, + and applying decorations, because windows which fill the screen are + considered "fullscreen" and it affects their layer */ + client_calc_layer(self); + + if (fs) { + /* try focus us when we go into fullscreen mode */ + client_focus(self); + } } static void client_iconify_recursive(ObClient *self, @@ -2922,8 +2945,8 @@ void client_maximize(ObClient *self, gboolean max, gint dir) if (dir == 2 && !self->max_vert) return; } - /* we just tell it to configure in the same place and client_configure - worries about filling the screen with the window */ + /* these will help configure_full figure out which screen to fill with + the window */ x = self->area.x; y = self->area.y; w = self->area.width; @@ -2941,34 +2964,23 @@ void client_maximize(ObClient *self, gboolean max, gint dir) self->pre_max_area.width, self->area.height); } } else { - Rect *a; - - a = screen_area_monitor(self->desktop, 0); if ((dir == 0 || dir == 1) && self->max_horz) { /* horz */ - if (self->pre_max_area.width > 0) { - x = self->pre_max_area.x; - w = self->pre_max_area.width; + g_assert(self->pre_max_area.width > 0); - RECT_SET(self->pre_max_area, 0, self->pre_max_area.y, - 0, self->pre_max_area.height); - } else { - /* pick some fallbacks... */ - x = a->x + a->width / 4; - w = a->width / 2; - } + x = self->pre_max_area.x; + w = self->pre_max_area.width; + + RECT_SET(self->pre_max_area, 0, self->pre_max_area.y, + 0, self->pre_max_area.height); } if ((dir == 0 || dir == 2) && self->max_vert) { /* vert */ - if (self->pre_max_area.height > 0) { - y = self->pre_max_area.y; - h = self->pre_max_area.height; + g_assert(self->pre_max_area.height > 0); - RECT_SET(self->pre_max_area, self->pre_max_area.x, 0, - self->pre_max_area.width, 0); - } else { - /* pick some fallbacks... */ - y = a->y + a->height / 4; - h = a->height / 2; - } + y = self->pre_max_area.y; + h = self->pre_max_area.height; + + RECT_SET(self->pre_max_area, self->pre_max_area.x, 0, + self->pre_max_area.width, 0); } } @@ -3207,7 +3219,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) action = self->demands_attention ? prop_atoms.net_wm_state_remove : prop_atoms.net_wm_state_add; - else if (state == prop_atoms.openbox_wm_state_undecorated) + else if (state == prop_atoms.ob_wm_state_undecorated) action = undecorated ? prop_atoms.net_wm_state_remove : prop_atoms.net_wm_state_add; } @@ -3237,7 +3249,7 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) below = TRUE; } else if (state == prop_atoms.net_wm_state_demands_attention) { demands_attention = TRUE; - } else if (state == prop_atoms.openbox_wm_state_undecorated) { + } else if (state == prop_atoms.ob_wm_state_undecorated) { undecorated = TRUE; } @@ -3264,11 +3276,12 @@ void client_set_state(ObClient *self, Atom action, glong data1, glong data2) below = FALSE; } else if (state == prop_atoms.net_wm_state_demands_attention) { demands_attention = FALSE; - } else if (state == prop_atoms.openbox_wm_state_undecorated) { + } else if (state == prop_atoms.ob_wm_state_undecorated) { undecorated = FALSE; } } } + if (max_horz != self->max_horz || max_vert != self->max_vert) { if (max_horz != self->max_horz && max_vert != self->max_vert) { /* toggling both */ @@ -3294,24 +3307,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 */ } @@ -3326,8 +3345,6 @@ ObClient *client_focus_target(ObClient *self) gboolean client_can_focus(ObClient *self) { - XEvent ev; - /* choose the correct target */ self = client_focus_target(self); @@ -3337,24 +3354,6 @@ gboolean client_can_focus(ObClient *self) if (!(self->can_focus || self->focus_notify)) return FALSE; - /* do a check to see if the window has already been unmapped or destroyed - do this intelligently while watching out for unmaps we've generated - (ignore_unmaps > 0) */ - if (XCheckTypedWindowEvent(ob_display, self->window, - DestroyNotify, &ev)) { - XPutBackEvent(ob_display, &ev); - return FALSE; - } - while (XCheckTypedWindowEvent(ob_display, self->window, - UnmapNotify, &ev)) { - if (self->ignore_unmaps) { - self->ignore_unmaps--; - } else { - XPutBackEvent(ob_display, &ev); - return FALSE; - } - } - return TRUE; } @@ -3385,13 +3384,14 @@ gboolean client_focus(ObClient *self) if (keyboard_interactively_grabbed()) keyboard_interactive_cancel(); + xerror_set_ignore(TRUE); + xerror_occured = FALSE; + if (self->can_focus) { /* This can cause a BadMatch error with CurrentTime, or if an app passed in a bad time for _NET_WM_ACTIVE_WINDOW. */ - xerror_set_ignore(TRUE); XSetInputFocus(ob_display, self->window, RevertToPointerRoot, event_curtime); - xerror_set_ignore(FALSE); } if (self->focus_notify) { @@ -3409,17 +3409,9 @@ gboolean client_focus(ObClient *self) XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce); } -#ifdef DEBUG_FOCUS - ob_debug("%sively focusing %lx at %d\n", - (self->can_focus ? "act" : "pass"), - self->window, (gint) event_curtime); -#endif + xerror_set_ignore(FALSE); - /* Cause the FocusIn to come back to us. Important for desktop switches, - since otherwise we'll have no FocusIn on the queue and send it off to - the focus_backup. */ - XSync(ob_display, FALSE); - return TRUE; + return !xerror_occured; } /*! Present the client to the user. @@ -3589,16 +3581,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 */ } } @@ -3729,8 +3718,6 @@ ObClient *client_search_transient(ObClient *self, ObClient *search) if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \ continue; \ if(cur->iconic) \ - continue; \ - if(cur->layer == c->layer) \ continue; #define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \