window on-move / move inconsistency: is this a bug?

46 просмотров
Перейти к первому непрочитанному сообщению

Simon Schlee

не прочитано,
21 нояб. 2019 г., 15:41:3821.11.2019
– Racket Users
Hello,

I am writing a gui application it is supposed to save the position of the window and upon restart restore the position.
For this I get the position via overriding the on-move method of frame%.
Upon restoring I call (send frame move x y).

The problem is that on my system (linux manjaro xfce gtk) move seems to treat the position as the outer window position (left-top of the decorated window).
When move is called and x y is different than what is returned via get-x and get-y then on-move is called two times the first time with x and y.
The second time with the delta added which corresponds to outer-window-pos+delta = inner-window-pos.

(send frame move outer-x outer-y) -> (on-move outer-x outer-y) -> (on-move inner-x inner-y)

The resulting problem is that after every restart the window moves by the delta because move adds the delta.
To me it seems like on-move should only be called once after a call to move and move should take inner-xy directly.
That would mean it sets the position of the inner-window-coordinate instead of setting the outer position.

Here is an example showing the move behaviour:
#lang racket/gui

(define moveframe%
  (class frame%
    (super-new)

    (define/override (on-move x y)
      (displayln (format "~a ~a" x y)))))

(define (example)
  (define f (new moveframe% [label "move frame"] [width 300] [height 300]))
  (define (m msg x y)
    (displayln (~a msg " " x " " y ":"))
    (send f move x y))

  (m "init" 100 100)
  (send f show #t)
  (sleep/yield 1)
  (m "reset" 100 100)
  (sleep/yield 1)
  ;; this depends on the window decoration specific delta which is (1 24) on my system
  (m "stays the same, because x y are already" (send f get-x) (send f get-y))
  (sleep/yield 1)
  (m "window decoration delta gets added" (add1 (send f get-x)) (send f get-y))
  (sleep/yield 1)
  (m "window decoration delta gets added again" (add1 (send f get-x)) (send f get-y))
  (sleep/yield 1)
  (send f show #f))

(module+ main
  (example))

;; OUTPUT
;; init 100 100:
;; 100 100
;; 101 124
;; reset 100 100:
;; 100 100
;; 101 124
;; stays the same, because x y are already 101 124:
;; window decoration delta gets added 102 124:
;; 102 124
;; 103 148
;; window decoration delta gets added again 104 148:
;; 104 148
;; 105 172


And here is an ugly workaround I created that calculates the delta between the outer and inner of the window:
#lang racket

(provide get-delta)

(require racket/gui/base)

(define deltaframe%
  (class frame%
    (init-field channel)
    (super-new [label "get-delta-frame"])

    (define ch channel)
    (define first-pos #f)
    (define/override (on-move x y)
      (when ch
        (if (not first-pos)
            (set! first-pos (list x y))
            (begin
              (calc-delta ch first-pos (list x y))
              (set! ch #f)))))

    (define (calc-delta ch first second)
      (match-define (list hx hy) first)
      (match-define (list vx vy) second)
      (define delta (list (- hx vx) (- hy vy)))
      (thread
       (thunk
        (channel-put ch delta)
        (send this show #f))))

    (send this move 100 100)
    (send this show #t)))

(define (get-delta/fetch)
  (define ch (make-channel))
  (thread
   (thunk (new deltaframe% [channel ch])))
  (define (loop)
    (sync (handle-evt ch (λ (delta) delta))
          (handle-evt always-evt (λ (x) (sleep/yield 0) (loop)))))
  (loop))

(define delta #f)
(define (get-delta)
  (set! delta (get-delta/fetch))
  (set! get-delta (λ () delta))
  delta)

;; result of get-delta on my system: (list -1 -24)

Does somebody else experience this behaviour?

Simon Schlee

не прочитано,
1 дек. 2019 г., 11:58:3901.12.2019
– Racket Users

Alex Harsanyi

не прочитано,
1 дек. 2019 г., 19:21:3301.12.2019
– Racket Users

On Monday, December 2, 2019 at 12:58:39 AM UTC+8, Simon Schlee wrote:

Based on you description, it seems that the window manager you use on Linux will adjust the window position to make room for the border, but this seems to be specific to the window manager itself.  It is not necessarily a bug that `on-move` is called multiple times and not always in response to calling the `frame%/move`  method (for example, it will be called when the windows is dragged with the mouse).  

This does not seem like a Racket GUI problem to me: I think that if you wrote a GTK application in C, the behavior would be the same.

Also the windows platform is not without its quirks in this regard: if you use `frame%/move` to move the window to 0,0, you'll notice that the top menu bar is lined up with the top of the screen, but there is an 8 pixel gap on the left.  This is because, while only a 1 pixel border is drawn around the window, there are an extra 8 pixels of invisible border, so the user can find the resize handle for the window.  Visually, moving a window to 0,0 will not move it to the top-left corner of the screen.

On Windows, there are API calls you can access using FFI, which allow calculating the window border to adjust for it.  I suspect there are similar APIs on Linux for GTK.

Alex.

Simon Schlee

не прочитано,
2 дек. 2019 г., 12:48:0802.12.2019
– Racket Users
Yes, when I put on my pragmatic thinking hat, I certainly agree with you.
But it also makes me think about whether I should create a utility library which does a more abstracted window placement and restoring.
That library would care more about logical "human" positioning and for example snap to screens and possibly use platform specific code like you suggested.
Currently such a library seems to be nice to have, but not that urgent to me.

On the other hand when I play devil's advocate I think racket/gui is a cross-platform gui library and should have a highlevel api where these platform specific quirks don't leak through.

I am unsure what is most reasonable and the better approach, I guess changing the move behavior might be difficult because of backwards compatibility,
so the utility library might be the way to go.
Ответить всем
Отправить сообщение автору
Переслать
0 новых сообщений