unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Patch to fix frame positioning bug on Windows with (make-frame '((left . -1)))
@ 2005-01-11 20:30 Francis Litterio
  2005-01-12 20:04 ` Jan D.
  0 siblings, 1 reply; 5+ messages in thread
From: Francis Litterio @ 2005-01-11 20:30 UTC (permalink / raw
  Cc: emacs-devel

Using Emacs built from CVS source code on Windows XP, the frame created
using the following Emacs-Lisp code is positioned such that the
rightmost 7 pixels of the frame are off the right edge of the screen:

  (make-frame '((width . 80) (height . 20) (top . 0) (left . -1)))

Those 7 pixels encompass the border of the Windows frame and some of the
right fringe.  This may have been caused by revision 1.220 of w32term.c
in which function x_calc_absolute_position() was changed:

  revision 1.220
  date: 2004/12/11 21:12:45;  author: jhd;  state: Exp;  lines: +0 -30
  * w32term.c (x_calc_absolute_position): Remove calculation of
  difference between inner and outer window.  Don't subtract difference
  for left and top calculations.

The below patch solves the problem but it may not be optimal because it
simply subtracts 7 from the computed value of f->left_pos.

One risk I see in this solution is that the user can change the Active
Window Border size to have any pixel width (right click on the desktop,
choose Properties, choose Appeareance, click Advanced, choose Active
Window Border from the Item listbox).  This code (both with and without
my patch) does not take the user-configurable size of the Active Window
Border into account.


I hope this helps.
--
Francis Litterio
franl <at> world . std . com


--- w32term.c	03 Jan 2005 17:52:51 -0500	1.221
+++ w32term.c	11 Jan 2005 15:27:02 -0500	
@@ -5381,7 +5381,8 @@
   if (flags & XNegative)
     f->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
 		   - FRAME_PIXEL_WIDTH (f)
-		   + f->left_pos);
+		   + f->left_pos
+		   - 7);
 
   if (flags & YNegative)
     f->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height





^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Patch to fix frame positioning bug on Windows with (make-frame '((left . -1)))
  2005-01-11 20:30 Patch to fix frame positioning bug on Windows with (make-frame '((left . -1))) Francis Litterio
@ 2005-01-12 20:04 ` Jan D.
  2005-01-12 20:45   ` Francis Litterio
  0 siblings, 1 reply; 5+ messages in thread
From: Jan D. @ 2005-01-12 20:04 UTC (permalink / raw
  Cc: help-emacs-windows, emacs-devel

> Using Emacs built from CVS source code on Windows XP, the frame created
> using the following Emacs-Lisp code is positioned such that the
> rightmost 7 pixels of the frame are off the right edge of the screen:
>
>   (make-frame '((width . 80) (height . 20) (top . 0) (left . -1)))
>
> Those 7 pixels encompass the border of the Windows frame and some of  
> the
> right fringe.  This may have been caused by revision 1.220 of w32term.c
> in which function x_calc_absolute_position() was changed:
>
>   revision 1.220
>   date: 2004/12/11 21:12:45;  author: jhd;  state: Exp;  lines: +0 -30
>   * w32term.c (x_calc_absolute_position): Remove calculation of
>   difference between inner and outer window.  Don't subtract difference
>   for left and top calculations.
>
> The below patch solves the problem but it may not be optimal because it
> simply subtracts 7 from the computed value of f->left_pos.

Can you verify if your change has any impact on this bug:

http://lists.gnu.org/archive/html/emacs-pretest-bug/2004-11/ 
msg00519.html

This was the reason a change was made.  It may be impossible to get  
Emacs to work correctly on W32.  Just adding 7 is no good, as you self  
pointed out, a more general solution must be found.

	Jan D.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Patch to fix frame positioning bug on Windows with (make-frame '((left . -1)))
  2005-01-12 20:04 ` Jan D.
@ 2005-01-12 20:45   ` Francis Litterio
  2005-01-13  2:59     ` Francis Litterio
  0 siblings, 1 reply; 5+ messages in thread
From: Francis Litterio @ 2005-01-12 20:45 UTC (permalink / raw
  Cc: help-emacs-windows

Jan D. wrote:

>> Using Emacs built from CVS source code on Windows XP, the frame created
>> using the following Emacs-Lisp code is positioned such that the
>> rightmost 7 pixels of the frame are off the right edge of the screen:
>>
>>   (make-frame '((width . 80) (height . 20) (top . 0) (left . -1)))
...
>> The below patch solves the problem but it may not be optimal because it
>> simply subtracts 7 from the computed value of f->left_pos.
>
> Can you verify if your change has any impact on this bug:
>
> http://lists.gnu.org/archive/html/emacs-pretest-bug/2004-11/msg00519.html
>
> This was the reason a change was made.  It may be impossible to get
> Emacs to work correctly on W32.  Just [subtracting] 7 is no good, as
> you self pointed out, a more general solution must be found.

My change breaks the fix for that bug, so I'm going to investigate
further.

In my testing, I noticed that (make-frame '((top . -1))) on Windows
suffers an even worse positioning error -- about 30 pixels at the bottom
of the frame fall off the bottom of the screen!

I would think that when a frame is positioned so that it is completely
visible, we have the following variables and relations:

  OUTER-LEFT: The number of pixels between the left screen edge
	      and the left border drawn by Windows of the frame.
	      This can be 0.

  LEFT-BORDER: The width of the left border drawn by Windows (in pixels).

  FRAME-CONTENT-WIDTH: The width of the frame content, including
		       the fringes but not including the left and
		       right borders drawn by Windows.

  RIGHT-BORDER: The width of the right border drawn by Windows (in
		pixels).

  OUTER-RIGHT: The number of pixels between the right screen edge
	       and the right border drawn by Windows of the frame.
	       This can be 0.

  DISPLAY-WIDTH: The width of the display (in pixels).

and finally this relation should hold:

  DISPLAY-WIDTH = OUTER-LEFT + LEFT-BORDER + FRAME-CONTENT-WIDTH +
		  RIGHT-BORDER + OUTER-RIGHT

A similar relation can be constructed for the vertical screen
dimension.

Given this model, we should be able to make w32term.c position frames
consistently, regardless of whether the 'top or 'left frame parameter
was positive or negative (modulo the issue with the user being able to
change the width of the border drawn by Windows -- but it should work
with Windows' default border sizes).
--
Francis Litterio
franl <at> world . std . com

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Patch to fix frame positioning bug on Windows with (make-frame '((left . -1)))
  2005-01-12 20:45   ` Francis Litterio
@ 2005-01-13  2:59     ` Francis Litterio
  2005-01-13  3:37       ` Francis Litterio
  0 siblings, 1 reply; 5+ messages in thread
From: Francis Litterio @ 2005-01-13  2:59 UTC (permalink / raw
  Cc: help-emacs-windows

Francis Litterio wrote:

> Jan D. wrote:

>> Can you verify if your change has any impact on this bug:
>>
>> http://lists.gnu.org/archive/html/emacs-pretest-bug/2004-11/msg00519.html
>>
>> This was the reason a change was made.  It may be impossible to get
>> Emacs to work correctly on W32.  Just [subtracting] 7 is no good, as
>> you self pointed out, a more general solution must be found.
>
> My change breaks the fix for that bug, so I'm going to investigate
> further.

OK, I think I've gotten to the bottom of the issue.  The above bug
report by Drew Adams contains an incorrect assumption in step #2 of the
steps to reproduce:

> 1. Position a new frame at the left border (the position isn't important,
> but keep track of the position you use - using 0 makes it easier). Evaluate
> (assq 'left (frame-parameters nil)), getting, for example, (left . 0).
> 
> 2. Measure the frame width in pixels: (frame-pixel-width nil), getting, for
> example, 600.

600 is not the width of the frame in pixels.  It is the width of the
frame's client area in pixels.  The window manager (i.e., Windows) draws
left and right borders on either side of the client area, but
frame-pixel-width does not include those borders in the value it
returns..

So the value computed in step #2 above should be:

        (+ (frame-pixel-width nil) 6 6)
        => 612

Assuming his window manager borders are 6 pixels wide.

> 3. Measure the display width in pixels: (display-pixel-width nil), getting,
> for example, 1280.
> 
> 4. Calculate the distance of the frame's right edge from the display's right
> edge, getting, for example, 1280 - 600 = 680.

In step #4, the calculation of the frame's right edge from the display's
right edit should be:

        1280 - 612 = 668

Actually, since a 'left parameter of 0 means "flush against the left
edge of the screen" but -1 means "flush against the right edge of the
screen", that calculation should be:

        1280 - 612 + 1 = 669

> 5. Change the frame's left parameter to the negation of the value in #4, for
> example: (modify-frame-parameters nil '((left . -680))). According to the
> doc, this positions the right edge of the frame 680 pixels from the right
> edge of the display.
> 
> However the frame has in fact shifted 12 pixels to the left.

The reason for this movement is that setting the 'left parameter to -680
was wrong.  It should have been set to -669.

To demonstrate that the window borders must be taken into account when
computing the negative 'left frame parameter, evaluate the below form in
a frame that is completely visible (no parts of the frame are
off-screen).  Evaluating this form should not move the frame at all,
assuming your window manager draws left and right borders that are 4
pixels each (change the two 4's if your borders are different):

(let ((negative-left (- (+ 1 (- (display-pixel-width)
                                (+ 4 4
                                   (frame-pixel-width nil)
                                   (frame-parameter nil 'left)))))))
  (modify-frame-parameters nil `((left . ,negative-left))))

On Windows, Emacs does not have to take the window manager borders into
account when positioning frames using positive 'left and 'top
parameters.  Positive 'left and 'top parameters are simply passed
directly to Windows, which is why this form:

        (make-frame '((top . 0) (left . 0)))

positions the frame with the Windows borders flush against the left and
top of the screen.  This is desirable behavior.

The only time that Emacs needs to take the window manager borders into
account is when it converts a negative 'left or 'top parameter to an
equivalent positive value, which is done in x_calc_absolute_position():

    void
    x_calc_absolute_position (f)
         struct frame *f;
    {
      int flags = f->size_hint_flags;

      /* Treat negative positions as relative to the leftmost bottommost
         position that fits on the screen.  */
      if (flags & XNegative)
        f->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
                       - FRAME_PIXEL_WIDTH (f)
                       + f->left_pos);

      if (flags & YNegative)
        f->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
                      - FRAME_PIXEL_HEIGHT (f)
                      + f->top_pos);
      /* The left_pos and top_pos
         are now relative to the top and left screen edges,
         so the flags should correspond.  */
      f->size_hint_flags &= ~ (XNegative | YNegative);
    }

and nowhere else (that I can find).  Thus, to fix both the bug reported in:

  http://lists.gnu.org/archive/html/emacs-pretest-bug/2004-11/msg00519.html

and my bug, the above function needs to compute f->left_pos like this:

        f->left_pos = (FRAME_W32_DISPLAY_INFO (f)->width
                       - FRAME_PIXEL_WIDTH (f)
                       + f->left_pos
                       - (FRAME_W32_VERTICAL_BORDER_WIDTH * 2) - 1);

where FRAME_W32_VERTICAL_BORDER_WIDTH is a proposed macro that evaluates
to the pixel width of one vertical border drawn by Windows.  On my
system, it would expand to 4.  On other Windows system, it may be
different.  Worse, under XP, the user can change it interactively using
the Appearance tab on the desktop properties dialog.

Similarly, f->top_pos should be computed like this:

        f->top_pos = (FRAME_W32_DISPLAY_INFO (f)->height
                      - FRAME_PIXEL_HEIGHT (f)
                      + f->top_pos
                      - (FRAME_W32_TOP_BORDER_WIDTH +
                         FRAME_W32_BOTTOM_BORDER_WIDTH) - 1);

This needs two new macros, because the top and bottom borders have
different sizes.

The question is: What is the correct implementation of these new macros?

On my system (Windows XP, with ), these values work:

        #define FRAME_W32_VERTICAL_BORDER_WIDTH 4
        #define FRAME_W32_TOP_BORDER_WIDTH 25
        #define FRAME_W32_BOTTOM_BORDER_WIDTH 4

I have build Emacs with the above change (and the above macro values),
and when I evaluate:

        (make-frame '((top . -1) (left . -1)))

the new frame is perfectly positioned flush against the right and bottom
edges of the display.

I hope this helps.
--
Francis Litterio
franl <at> world . std . com

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Patch to fix frame positioning bug on Windows with (make-frame '((left . -1)))
  2005-01-13  2:59     ` Francis Litterio
@ 2005-01-13  3:37       ` Francis Litterio
  0 siblings, 0 replies; 5+ messages in thread
From: Francis Litterio @ 2005-01-13  3:37 UTC (permalink / raw
  Cc: help-emacs-windows

I wrote:

> To demonstrate that the window borders must be taken into account when
> computing the negative 'left frame parameter, evaluate the below form in
> a frame that is completely visible (no parts of the frame are
> off-screen).  Evaluating this form should not move the frame at all,
> assuming your window manager draws left and right borders that are 4
> pixels each (change the two 4's if your borders are different):
>
> (let ((negative-left (- (+ 1 (- (display-pixel-width)
>                                 (+ 4 4
>                                    (frame-pixel-width nil)
>                                    (frame-parameter nil 'left)))))))
>   (modify-frame-parameters nil `((left . ,negative-left))))

Sorry.  You will only see no frame movement when evaluating the above
form if you have already patched x_calc_absolute_position() as described
in the parent of this article.
--
Francis Litterio
franl <at> world . std . com

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2005-01-13  3:37 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-01-11 20:30 Patch to fix frame positioning bug on Windows with (make-frame '((left . -1))) Francis Litterio
2005-01-12 20:04 ` Jan D.
2005-01-12 20:45   ` Francis Litterio
2005-01-13  2:59     ` Francis Litterio
2005-01-13  3:37       ` Francis Litterio

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).