// Sometimes window managers are really slow about // re-implemented here because under Fluxbox, win.WMMove() results in the window // growing vertically by the height of the titlebar! // So we snapshot the size of the window before we move it, // move it, compare the sizes, then resize it vertically to be in line with our intentions // // this is synchronous: it waits for the window to finish moving before it releases control // because it would be impossible to selectivley poll for just the move. func Move(win *xwindow.Window, x, y int) error { // snapshot both sorts of window geometries decor_geom, geom, err := Geometries(win) if err != nil { return err } log.Printf("Move: detected geometry to be %v\n", geom) // move the window, then wait for it to finish moving err = win.WMMove(x, y) if err != nil { return err } // this waits 30MS under non-Fluxbox window manager // WHAT DO err = PollFor(win, GeometryDiffers(geom)) if err != nil { // if we had a timeout, that means that the geometry didn't derp during // moving, and everything is A-OK! // skip the rest of the function if _, wasTimeout := err.(*TimeoutError); wasTimeout { return nil } return err } // compare window widths before/after move _, post_move_base, err := Geometries(win) if err != nil { return err } delta_w := post_move_base.Width() - geom.Width() delta_h := post_move_base.Height() - geom.Height() if delta_h != 0 || delta_w != 0 { // fluxbox has done it again. We issued a move, and we got a taller window, too! log.Printf("Move: resetting dimensions to %v due to w/h delta: %v/%v\n", geom, delta_w, delta_h) err = win.WMResize(geom.Width(), geom.Height()) if err != nil { return err } // wait for that to succeed err = PollFor(win, GeometryDiffers(post_move_base)) if err != nil { return err } } // make sure window did actually move err = PollFor(win, DecorDiffers(decor_geom)) if err != nil { // if we had a timeout, that means that the window didn't move // we want to send an error mentioning that fact specifically // instead of a generic "lol timeout happan in polling :DDD" if te, wasTimeout := err.(*TimeoutError); wasTimeout { return &TimeoutError{"Move: window didn't move", te.Timeout} } // return whatever other error stymied the polling return err } return nil }