X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=openbox%2Fclient.c;h=4cfece1dd2e8996bcc83632ab195e8b70ebfab46;hb=94c95663a86b1b40463fcd1e25a9ac4bc10954c1;hp=a80159786b8ca9c9f957e2b04dd28e9cedf3ad54;hpb=cc2237bb4f1ff3f32b58e8714f7ba72538df0d91;p=chaz%2Fopenbox diff --git a/openbox/client.c b/openbox/client.c index a8015978..4cfece1d 100644 --- a/openbox/client.c +++ b/openbox/client.c @@ -78,7 +78,8 @@ static void client_get_colormap(ObClient *self); static void client_change_allowed_actions(ObClient *self); static void client_change_state(ObClient *self); static void client_change_wm_state(ObClient *self); -static void client_apply_startup_state(ObClient *self); +static void client_apply_startup_state(ObClient *self, + gint x, gint y, gint w, gint h); static void client_restore_session_state(ObClient *self); static gboolean client_restore_session_stacking(ObClient *self); static ObAppSettings *client_get_settings_state(ObClient *self); @@ -240,7 +241,8 @@ void client_manage(Window window) XWMHints *wmhint; gboolean activate = FALSE; ObAppSettings *settings; - gint placex, placey; + gint placex, placey, placew, placeh; + gboolean transient = FALSE; grab_server(TRUE); @@ -317,11 +319,11 @@ void client_manage(Window window) 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 */ + /* 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); + client_setup_decor_and_functions(self, FALSE); { Time t = sn_app_started(self->startup_id, self->class); @@ -347,15 +349,19 @@ void client_manage(Window window) client_search_focus_tree_full(self)) && /* this checks for focus=false for the window */ (!settings || settings->focus != 0) && - /* note the check against Type_Normal/Dialog, not client_normal(self), - which would also include other types. in this case we want more - strict rules for focus */ + /* note the check against type Normal/Dialog/Utility, + not client_normal(self), which would also include other types. + in this case we want more strict rules for focus */ (self->type == OB_CLIENT_TYPE_NORMAL || + self->type == OB_CLIENT_TYPE_UTILITY || self->type == OB_CLIENT_TYPE_DIALOG)) { activate = TRUE; } + /* remove the client's border */ + XSetWindowBorderWidth(ob_display, self->window, 0); + /* adjust the frame to the client's size before showing or placing the window */ frame_adjust_area(self->frame, FALSE, TRUE, FALSE); @@ -364,18 +370,18 @@ void client_manage(Window window) /* where the frame was placed is where the window was originally */ placex = self->area.x; placey = self->area.y; + placew = self->area.width; + placeh = self->area.height; /* figure out placement for the window if the window is new */ 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" : (self->positioned == (PPosition | USPosition) ? "program + user specified" : - "BADNESS !?")))), self->area.x, self->area.y); + "BADNESS !?")))), placex, placey); ob_debug("Sized: %s @ %d %d\n", (!self->sized ? "no" : @@ -383,39 +389,14 @@ void client_manage(Window window) (self->sized == USSize ? "user specified" : (self->sized == (PSize | USSize) ? "program + user specified" : - "BADNESS !?")))), self->area.width, self->area.height); + "BADNESS !?")))), placew, placeh); + /* splash screens are also returned as TRUE for transient, + and so will be forced on screen below */ transient = place_client(self, &placex, &placey, settings); - /* if the window isn't user-positioned, then make it fit inside - the visible screen area on its monitor. - - the monitor is chosen by place_client! */ - if (!(self->sized & USSize)) { - /* make a copy to modify */ - Rect a = *screen_area_monitor(self->desktop, client_monitor(self)); - - /* 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; - - /* fit the window inside the area */ - if (self->area.width > a.width || self->area.height > a.height) { - self->area.width = MIN(self->area.width, a.width); - self->area.height = MIN(self->area.height, a.height); - - ob_debug("setting window size to %dx%d\n", - self->area.width, self->area.height); - - /* adjust the frame to the client's new size */ - frame_adjust_area(self->frame, FALSE, TRUE, FALSE); - frame_adjust_client_area(self->frame); - } - } - /* make sure the window is visible. */ - client_find_onscreen(self, &placex, &placey, - self->area.width, self->area.height, + client_find_onscreen(self, &placex, &placey, placew, placeh, /* non-normal clients has less rules, and windows that are being restored from a session do also. we can assume you want @@ -425,40 +406,66 @@ void client_manage(Window window) place.c or by the user are allowed partially off-screen and on xinerama divides (ie, it is up to the placement routines to avoid - the xinerama divides) */ - transient || - (!(self->positioned & USPosition) && - client_normal(self) && - !self->session)); + the xinerama divides) + + splash screens get "transient" set to TRUE by + the place_client call + */ + ob_state() == OB_STATE_RUNNING && + (transient || + (!(self->positioned & USPosition) && + client_normal(self) && + !self->session))); } - ob_debug("placing window 0x%x at %d, %d with size %d x %d\n", - 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); + /* if the window isn't user-sized, then make it fit inside + the visible screen area on its monitor. Use basically the same rules + for forcing the window on screen in the client_find_onscreen call. - /* do this after the window is placed, so the premax/prefullscreen numbers - won't be all wacko!! + do this after place_client, it chooses the monitor! + + splash screens get "transient" set to TRUE by + the place_client call */ - client_apply_startup_state(self); + if (ob_state() == OB_STATE_RUNNING && + (transient || + (!(self->sized & USSize) && + client_normal(self) && + !self->session))) + { + /* make a copy to modify */ + Rect a = *screen_area_monitor(self->desktop, client_monitor(self)); - /* move the client to its placed position, or it it's already there, - generate a ConfigureNotify telling the client where it is. + /* 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; - do this after adjusting the frame. otherwise it gets all weird and - clients don't work right + /* 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); - 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, - self->border_width, - FALSE, TRUE); + ob_debug("setting window size to %dx%d\n", + self->area.width, self->area.height); + } + } + + + ob_debug("placing window 0x%x at %d, %d with size %d x %d. " + "some restrictions may apply\n", + self->window, placex, placey, placew, placeh); + if (self->session) + ob_debug(" but session requested %d, %d %d x %d instead, " + "overriding\n", + self->session->x, self->session->y, + self->session->w, self->session->h); + + /* do this after the window is placed, so the premax/prefullscreen numbers + won't be all wacko!! + this also places the window + */ + client_apply_startup_state(self, placex, placey, placew, placeh); if (activate) { guint32 last_time = focus_client ? @@ -575,7 +582,7 @@ void client_manage(Window window) g_free(settings); ob_debug("Managed window 0x%lx plate 0x%x (%s)\n", - window, self->frame->plate, self->class); + window, self->frame->window, self->class); return; } @@ -598,7 +605,7 @@ ObClient *client_fake_manage(Window window) uses too. this returns a shallow copy that needs to be freed */ settings = client_get_settings_state(self); - client_setup_decor_and_functions(self); + client_setup_decor_and_functions(self, FALSE); /* create the decoration frame for the client window and adjust its size */ self->frame = frame_new(self); @@ -624,9 +631,10 @@ void client_unmanage(ObClient *self) { guint j; GSList *it; + gulong ignore_start; ob_debug("Unmanaging window: 0x%x plate 0x%x (%s) (%s)\n", - self->window, self->frame->plate, + self->window, self->frame->window, self->class, self->title ? self->title : ""); g_assert(self != NULL); @@ -635,13 +643,16 @@ void client_unmanage(ObClient *self) don't generate more events */ XSelectInput(ob_display, self->window, NoEventMask); + /* ignore enter events from the unmap so it doesnt mess with the focus */ + if (!client_focused(self) || !config_focus_under_mouse) + ignore_start = event_start_ignore_all_enters(); + frame_hide(self->frame); /* flush to send the hide to the server quickly */ XFlush(ob_display); - /* ignore enter events from the unmap so it doesnt mess with the - focus */ - event_ignore_all_queued_enters(); + if (!client_focused(self) || !config_focus_under_mouse) + event_end_ignore_all_enters(ignore_start); mouse_grab_for_client(self, FALSE); @@ -718,6 +729,9 @@ void client_unmanage(ObClient *self) self->functions = OB_CLIENT_FUNC_MOVE | OB_CLIENT_FUNC_RESIZE; self->decorations = 0; /* unmanaged windows have no decor */ + /* give the client its border back */ + XSetWindowBorderWidth(ob_display, self->window, self->border_width); + client_move_resize(self, a.x, a.y, a.width, a.height); } @@ -1140,6 +1154,9 @@ static void client_get_desktop(ObClient *self) for (it = self->group->members; it; it = g_slist_next(it)) { ObClient *c = it->data; + + if (c->desktop == DESKTOP_ALL) continue; + if (c != self) { if (first) { all = c->desktop; @@ -1595,9 +1612,7 @@ 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) +void client_setup_decor_and_functions(ObClient *self, gboolean reconfig) { /* start with everything (cept fullscreen) */ self->decorations = @@ -1753,6 +1768,9 @@ void client_setup_decor_and_functions(ObClient *self) } client_change_allowed_actions(self); + + if (reconfig) + client_reconfigure(self); } static void client_change_allowed_actions(ObClient *self) @@ -1814,7 +1832,7 @@ void client_reconfigure(ObClient *self) { client_configure(self, self->area.x, self->area.y, self->area.width, self->area.height, - self->border_width, FALSE, TRUE); + FALSE, TRUE); } void client_update_wmhints(ObClient *self) @@ -2301,7 +2319,7 @@ static void client_change_wm_state(ObClient *self) static void client_change_state(ObClient *self) { - gulong netstate[11]; + gulong netstate[12]; guint num; num = 0; @@ -2546,45 +2564,70 @@ gboolean client_enter_focusable(ObClient *self) } -static void client_apply_startup_state(ObClient *self) +static void client_apply_startup_state(ObClient *self, + gint x, gint y, gint w, gint h) { - /* set the desktop hint, to make sure that it always exists */ - PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop); + /* save the states that we are going to apply */ + gboolean iconic = self->iconic; + gboolean fullscreen = self->fullscreen; + gboolean undecorated = self->undecorated; + gboolean shaded = self->shaded; + gboolean demands_attention = self->demands_attention; + gboolean max_horz = self->max_horz; + gboolean max_vert = self->max_vert; + Rect oldarea; + gint l; + + /* turn them all off in the client, so they won't affect the window + being placed */ + self->iconic = self->fullscreen = self->undecorated = self->shaded = + self->demands_attention = self->max_horz = self->max_vert = FALSE; + + /* 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 + + do this before applying the states so they have the correct + pre-max/pre-fullscreen values + */ + client_try_configure(self, &x, &y, &w, &h, &l, &l, FALSE); + ob_debug("placed 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); + oldarea = self->area; /* save the area */ + RECT_SET(self->area, x, y, w, h); /* put where it should be for the premax stuff */ - /* these are in a carefully crafted order.. */ + /* apply the states. these are in a carefully crafted order.. */ - if (self->iconic) { - self->iconic = FALSE; + if (iconic) client_iconify(self, TRUE, FALSE, TRUE); - } - if (self->fullscreen) { - self->fullscreen = FALSE; + if (fullscreen) client_fullscreen(self, TRUE); - } - if (self->undecorated) { - self->undecorated = FALSE; + if (undecorated) client_set_undecorated(self, TRUE); - } - if (self->shaded) { - self->shaded = FALSE; + if (shaded) client_shade(self, TRUE); - } - if (self->demands_attention) { - self->demands_attention = FALSE; + if (demands_attention) client_hilite(self, TRUE); - } - if (self->max_vert && self->max_horz) { - self->max_vert = self->max_horz = FALSE; + if (max_vert && max_horz) client_maximize(self, TRUE, 0); - } else if (self->max_vert) { - self->max_vert = FALSE; + else if (max_vert) client_maximize(self, TRUE, 2); - } else if (self->max_horz) { - self->max_horz = FALSE; + else if (max_horz) client_maximize(self, TRUE, 1); + + /* 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); } + /* set the desktop hint, to make sure that it always exists */ + PROP_SET32(self->window, net_wm_desktop, cardinal, self->desktop); + /* nothing to do for the other states: skip_taskbar skip_pager @@ -2807,7 +2850,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, gint b, +void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gboolean user, gboolean final) { gint oldw, oldh; @@ -2827,14 +2870,12 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, SIZE_SET(self->logical_size, logicalw, logicalh); /* figure out if we moved or resized or what */ - moved = x != self->area.x || y != self->area.y; - resized = w != self->area.width || h != self->area.height || - b != self->border_width; + moved = (x != self->area.x || y != self->area.y); + resized = (w != self->area.width || h != self->area.height); oldw = self->area.width; oldh = self->area.height; RECT_SET(self->area, x, y, w, h); - self->border_width = b; /* for app-requested resizes, always resize if 'resized' is true. for user-requested ones, only resize if final is true, or when @@ -2845,16 +2886,9 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, /* if the client is enlarging, then resize the client before the frame */ if (send_resize_client && (w > oldw || h > oldh)) { - XWindowChanges changes; - changes.x = -self->border_width; - changes.y = -self->border_width; - changes.width = MAX(w, oldw); - changes.height = MAX(h, oldh); - changes.border_width = self->border_width; - XConfigureWindow(ob_display, self->window, - CWX|CWY|CWWidth|CWHeight|CWBorderWidth, - &changes); - /* resize the plate to show the client padding color underneath */ + XMoveResizeWindow(ob_display, self->window, + self->frame->size.left, self->frame->size.top, + MAX(w, oldw), MAX(h, oldh)); frame_adjust_client_area(self->frame); } @@ -2873,7 +2907,20 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, if (fmoved || fresized) frame_adjust_area(self->frame, fmoved, fresized, FALSE); - if ((!user || (user && final)) && !resized) + /* 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. + + 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 + 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)) { XEvent event; @@ -2905,22 +2952,15 @@ void client_configure(ObClient *self, gint x, gint y, gint w, gint h, gint b, FALSE, StructureNotifyMask, &event); } - /* if the client is shrinking, then resize the frame before the client */ - if (send_resize_client && (w <= oldw && h <= oldh)) { - /* resize the plate to show the client padding color underneath */ - frame_adjust_client_area(self->frame); + /* if the client is shrinking, then resize the frame before the client. - if (send_resize_client) { - XWindowChanges changes; - changes.x = -self->border_width; - changes.y = -self->border_width; - changes.width = w; - changes.height = h; - changes.border_width = self->border_width; - XConfigureWindow(ob_display, self->window, - CWX|CWY|CWWidth|CWHeight|CWBorderWidth, - &changes); - } + both of these resize sections may run, because the top one only resizes + in the direction that is growing + */ + if (send_resize_client && (w <= oldw || h <= oldh)) { + frame_adjust_client_area(self->frame); + XMoveResizeWindow(ob_display, self->window, + self->frame->size.left, self->frame->size.top, w, h); } XFlush(ob_display); @@ -2966,8 +3006,7 @@ void client_fullscreen(ObClient *self, gboolean fs) RECT_SET(self->pre_fullscreen_area, 0, 0, 0, 0); } - client_setup_decor_and_functions(self); - + client_setup_decor_and_functions(self, FALSE); client_move_resize(self, x, y, w, h); /* and adjust our layer/stacking. do this after resizing the window, @@ -3111,8 +3150,7 @@ void client_maximize(ObClient *self, gboolean max, gint dir) client_change_state(self); /* change the state hints on the client */ - client_setup_decor_and_functions(self); - + client_setup_decor_and_functions(self, FALSE); client_move_resize(self, x, y, w, h); } @@ -3217,8 +3255,7 @@ void client_set_desktop_recursive(ObClient *self, client_set_desktop_recursive(it->data, target, donthide); } -void client_set_desktop(ObClient *self, guint target, - gboolean donthide) +void client_set_desktop(ObClient *self, guint target, gboolean donthide) { self = client_search_top_normal_parent(self); client_set_desktop_recursive(self, target, donthide); @@ -3487,10 +3524,8 @@ gboolean client_focus(ObClient *self) self = client_focus_target(self); if (!client_can_focus(self)) { - if (!self->frame->visible) { - /* update the focus lists */ - focus_order_to_top(self); - } + ob_debug_type(OB_DEBUG_FOCUS, + "Client %s can't be focused\n", self->title); return FALSE; } @@ -3605,29 +3640,35 @@ void client_activate(ObClient *self, gboolean here, gboolean user) static void client_bring_windows_recursive(ObClient *self, guint desktop, gboolean helpers, - gboolean modals) + gboolean modals, + gboolean iconic) { GSList *it; for (it = self->transients; it; it = g_slist_next(it)) - client_bring_windows_recursive(it->data, desktop, helpers, modals); + client_bring_windows_recursive(it->data, desktop, + helpers, modals, iconic); if (((helpers && client_helper(self)) || - (modals && self->modal))&& - self->desktop != desktop && self->desktop != DESKTOP_ALL) + (modals && self->modal)) && + ((self->desktop != desktop && self->desktop != DESKTOP_ALL) || + (iconic && self->iconic))) { - client_set_desktop(self, desktop, FALSE); + if (iconic && self->iconic) + client_iconify(self, FALSE, TRUE, FALSE); + else + client_set_desktop(self, desktop, FALSE); } } void client_bring_helper_windows(ObClient *self) { - client_bring_windows_recursive(self, self->desktop, TRUE, FALSE); + client_bring_windows_recursive(self, self->desktop, TRUE, FALSE, FALSE); } void client_bring_modal_windows(ObClient *self) { - client_bring_windows_recursive(self, self->desktop, FALSE, TRUE); + client_bring_windows_recursive(self, self->desktop, FALSE, TRUE, TRUE); } gboolean client_focused(ObClient *self) @@ -3716,8 +3757,7 @@ void client_set_undecorated(ObClient *self, gboolean undecorated) (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_setup_decor_and_functions(self, TRUE); client_change_state(self); /* reflect this in the state hints */ } } @@ -3841,13 +3881,12 @@ ObClient *client_search_transient(ObClient *self, ObClient *search) } #define WANT_EDGE(cur, c) \ - if(cur == c) \ - continue; \ - if(!client_normal(cur)) \ + if (cur == c) \ continue; \ - if(screen_desktop != cur->desktop && cur->desktop != DESKTOP_ALL) \ + if (c->desktop != cur->desktop && cur->desktop != DESKTOP_ALL && \ + cur->desktop != screen_desktop) \ continue; \ - if(cur->iconic) \ + if (cur->iconic) \ continue; #define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \