unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* x-display-pixel-width/height inconsistency
@ 2013-03-19  0:39 YAMAMOTO Mitsuharu
  2013-03-19  1:34 ` Leo Liu
  2013-03-19 22:25 ` YAMAMOTO Mitsuharu
  0 siblings, 2 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-19  0:39 UTC (permalink / raw)
  To: emacs-devel

There is an inconsistency about the behavior of
x-display-pixel-width/height among multiple platforms under
multi-monitor environments.

The elisp info nodes "Multiple Terminals" and "Display Feature
Testing" say:

  ...

     On some "multi-monitor" setups, a single X display outputs to more
  than one physical monitor.  Currently, there is no way for Emacs to
  distinguish between the different physical monitors.

  ...

   -- Function: display-pixel-height &optional display
       This function returns the height of the screen in pixels.  On a
       character terminal, it gives the height in characters.

       For graphical terminals, note that on "multi-monitor" setups this
       refers to the pixel width for all physical monitors associated with
       DISPLAY.  *Note Multiple Terminals::.

   -- Function: display-pixel-width &optional display
       This function returns the width of the screen in pixels.  On a
       character terminal, it gives the width in characters.

       For graphical terminals, note that on "multi-monitor" setups this
       refers to the pixel width for all physical monitors associated with
       DISPLAY.  *Note Multiple Terminals::.

But the actual return value is different among the platforms:

  * X11 and Mac port: Dimension for all physical monitors, as
    documented above.

  * NS port: Dimension of some particular physical monitor determined
    by the argument.

  * W32 port: Dimension of the primary monitor. (Not actually tested,
    but guessed from the code and API documentations.)

I think these functions should behave consistently among multiple
platforms (probably in line with X11).

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19  0:39 YAMAMOTO Mitsuharu
@ 2013-03-19  1:34 ` Leo Liu
  2013-03-19  4:54   ` Xue Fuqiao
  2013-03-19 22:25 ` YAMAMOTO Mitsuharu
  1 sibling, 1 reply; 97+ messages in thread
From: Leo Liu @ 2013-03-19  1:34 UTC (permalink / raw)
  To: emacs-devel

Thanks a lot for taking a look at this.

On 2013-03-19 08:39 +0800, YAMAMOTO Mitsuharu wrote:
>   * X11 and Mac port: Dimension for all physical monitors, as
>     documented above.

BTW, I find this return value useless. I recently switched to two
monitors and was finding a way to progromaticly set up the geometry for
emacs. I have to make a small cli tool to do that.

I think `fit-frame-to-screen' would be a nice command for emacs to have.

Leo




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19  1:34 ` Leo Liu
@ 2013-03-19  4:54   ` Xue Fuqiao
  2013-03-19 15:41     ` Drew Adams
  0 siblings, 1 reply; 97+ messages in thread
From: Xue Fuqiao @ 2013-03-19  4:54 UTC (permalink / raw)
  To: Leo Liu; +Cc: emacs-devel

On Tue, 19 Mar 2013 09:34:10 +0800
Leo Liu <sdl.web@gmail.com> wrote:

> I think `fit-frame-to-screen' would be a nice command for emacs to have.

+1

-- 
Xue Fuqiao
http://www.gnu.org/software/emacs/



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

* RE: x-display-pixel-width/height inconsistency
  2013-03-19  4:54   ` Xue Fuqiao
@ 2013-03-19 15:41     ` Drew Adams
  2013-03-19 15:51       ` Leo Liu
  0 siblings, 1 reply; 97+ messages in thread
From: Drew Adams @ 2013-03-19 15:41 UTC (permalink / raw)
  To: 'Xue Fuqiao', 'Leo Liu'; +Cc: emacs-devel

> > I think `fit-frame-to-screen' would be a nice command for 
> > emacs to have.
> 
> +1

Not sure whether this is exactly what you have in mind (it does nothing special
wrt multiple displays).  But FWIW, command `maximize-frame' in `frame-cmds.el'
does that.  It also lets users reserve part of the display for the MS Windows
task bar or for the Mac "smart tool bar" (or whatever).

,----
| maximize-frame is an interactive compiled Lisp function in `frame-cmds'.
| (maximize-frame &optional DIRECTION FRAME)
| 
| Maximize selected frame horizontally, vertically, or both.
| With no prefix arg, maximize both directions.
| With a non-negative prefix arg, maximize vertically.
| With a negative prefix arg, maximize horizontally.
| 
| In Lisp code:
|  DIRECTION is the direction: `horizontal', `vertical', or `both'.
|  FRAME is the frame to maximize.
`----

Command `restore-frame' returns a frame to its pre-maximized size and position.
Command `toggle-max-frame' does both, alternating: maximize/restore.

code: http://www.emacswiki.org/emacs-en/download/frame-cmds.el

description: http://emacswiki.org/emacs/FullScreen#frame-cmds.el




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19 15:41     ` Drew Adams
@ 2013-03-19 15:51       ` Leo Liu
  2013-03-19 15:58         ` Drew Adams
  0 siblings, 1 reply; 97+ messages in thread
From: Leo Liu @ 2013-03-19 15:51 UTC (permalink / raw)
  To: Drew Adams; +Cc: emacs-devel

On 2013-03-19 23:41 +0800, Drew Adams wrote:
> Not sure whether this is exactly what you have in mind (it does nothing special
> wrt multiple displays).  But FWIW, command `maximize-frame' in `frame-cmds.el'
> does that.  It also lets users reserve part of the display for the MS Windows
> task bar or for the Mac "smart tool bar" (or whatever).

On big screens I don't have emacs maximised by default, I have width x
height specific to the resolution.

Leo



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

* RE: x-display-pixel-width/height inconsistency
  2013-03-19 15:51       ` Leo Liu
@ 2013-03-19 15:58         ` Drew Adams
  2013-03-20  0:55           ` Leo Liu
  0 siblings, 1 reply; 97+ messages in thread
From: Drew Adams @ 2013-03-19 15:58 UTC (permalink / raw)
  To: 'Leo Liu'; +Cc: emacs-devel

> > Not sure whether this is exactly what you have in mind (it 
> > does nothing special wrt multiple displays).  But FWIW,
> > command `maximize-frame' in `frame-cmds.el' does that.
> > It also lets users reserve part of the display for the MS
> > Windows task bar or for the Mac "smart tool bar" (or whatever).
> 
> On big screens I don't have emacs maximised by default, I have
> width x height specific to the resolution.

And?  How is that relevant?
What is the behavior you seek?




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19  0:39 YAMAMOTO Mitsuharu
  2013-03-19  1:34 ` Leo Liu
@ 2013-03-19 22:25 ` YAMAMOTO Mitsuharu
  2013-03-19 23:15   ` Dmitry Gutov
  1 sibling, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-19 22:25 UTC (permalink / raw)
  To: emacs-devel

>>>>> On Tue, 19 Mar 2013 09:39:07 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

> But the actual return value is different among the platforms:

>   * W32 port: Dimension of the primary monitor. (Not actually tested,
>     but guessed from the code and API documentations.)

Could someone using multi-monitor setups on W32 check if this guess is
correct?  I'm confused because an API reference in English (*1) says
"If this value (argument) is NULL, GetDC retrieves the DC for the
entire screen", whereas another reference in Japanese (*2) says "Given
NULL, GetDC retrieves the DC for the primary monitor.  To retrieve DCs
for other monitors, use EnumDisplayMonitors and CreateDC".

*1: http://msdn.microsoft.com/en-us/library/windows/desktop/dd144871(v=vs.85).aspx
*2: http://msdn.microsoft.com/ja-jp/library/cc428664.aspx

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19 22:25 ` YAMAMOTO Mitsuharu
@ 2013-03-19 23:15   ` Dmitry Gutov
  2013-03-19 23:52     ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Dmitry Gutov @ 2013-03-19 23:15 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

>>>>>> On Tue, 19 Mar 2013 09:39:07 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:
>
>> But the actual return value is different among the platforms:
>
>>   * W32 port: Dimension of the primary monitor. (Not actually tested,
>>     but guessed from the code and API documentations.)
>
> Could someone using multi-monitor setups on W32 check if this guess is
> correct?  I'm confused because an API reference in English (*1) says

It is correct.

> "If this value (argument) is NULL, GetDC retrieves the DC for the
> entire screen", whereas another reference in Japanese (*2) says "Given
> NULL, GetDC retrieves the DC for the primary monitor.  To retrieve DCs
> for other monitors, use EnumDisplayMonitors and CreateDC".

Sounds like the Japanese version is the correct one.



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19 23:15   ` Dmitry Gutov
@ 2013-03-19 23:52     ` YAMAMOTO Mitsuharu
  2013-03-20  0:12       ` Dmitry Gutov
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-19 23:52 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

>>>>> On Wed, 20 Mar 2013 03:15:06 +0400, Dmitry Gutov <dgutov@yandex.ru> said:

>>> But the actual return value is different among the platforms:
>> 
>>> * W32 port: Dimension of the primary monitor. (Not actually
>>> tested, but guessed from the code and API documentations.)
>> 
>> Could someone using multi-monitor setups on W32 check if this guess
>> is correct?  I'm confused because an API reference in English (*1)
>> says

> It is correct.

Thanks for checking.  Does the following patch give dimensions of all
physical monitors as in X11?  Do display-mm-height/width return
meaningful values?

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'src/w32fns.c'
*** src/w32fns.c	2013-03-10 22:55:25 +0000
--- src/w32fns.c	2013-03-19 23:47:14 +0000
***************
*** 4732,4746 ****
  If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
!   struct w32_display_info *dpyinfo = check_x_display_info (display);
!   HDC hdc;
!   int cap;
! 
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, VERTSIZE);
! 
!   ReleaseDC (dpyinfo->root_window, hdc);
  
    return make_number (cap);
  }
--- 4732,4741 ----
  If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
!   HDC hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
!   int cap = GetDeviceCaps (hdc, VERTSIZE);
  
!   DeleteDC (hdc);
  
    return make_number (cap);
  }
***************
*** 4752,4767 ****
  If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
!   struct w32_display_info *dpyinfo = check_x_display_info (display);
! 
!   HDC hdc;
!   int cap;
! 
!   hdc = GetDC (dpyinfo->root_window);
! 
!   cap = GetDeviceCaps (hdc, HORZSIZE);
  
!   ReleaseDC (dpyinfo->root_window, hdc);
  
    return make_number (cap);
  }
--- 4747,4756 ----
  If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
!   HDC hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
!   int cap = GetDeviceCaps (hdc, HORZSIZE);
  
!   DeleteDC (hdc);
  
    return make_number (cap);
  }

=== modified file 'src/w32term.c'
*** src/w32term.c	2013-03-15 10:07:29 +0000
--- src/w32term.c	2013-03-19 23:47:25 +0000
***************
*** 515,532 ****
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
    int pixels = GetDeviceCaps (dc, VERTRES);
!   ReleaseDC (NULL, dc);
    return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
    int pixels = GetDeviceCaps (dc, HORZRES);
!   ReleaseDC (NULL, dc);
    return pixels;
  }
  
--- 515,532 ----
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   HDC dc = CreateDC ("DISPLAY", NULL, NULL, NULL);
    int pixels = GetDeviceCaps (dc, VERTRES);
!   DeleteDC (dc);
    return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   HDC dc = CreateDC ("DISPLAY", NULL, NULL, NULL);
    int pixels = GetDeviceCaps (dc, HORZRES);
!   DeleteDC (dc);
    return pixels;
  }
  




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19 23:52     ` YAMAMOTO Mitsuharu
@ 2013-03-20  0:12       ` Dmitry Gutov
  2013-03-20  0:20         ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Dmitry Gutov @ 2013-03-20  0:12 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

>>>>>> On Wed, 20 Mar 2013 03:15:06 +0400, Dmitry Gutov <dgutov@yandex.ru> said:
>
>>>> But the actual return value is different among the platforms:
>>> 
>>>> * W32 port: Dimension of the primary monitor. (Not actually
>>>> tested, but guessed from the code and API documentations.)
>>> 
>>> Could someone using multi-monitor setups on W32 check if this guess
>>> is correct?  I'm confused because an API reference in English (*1)
>>> says
>
>> It is correct.
>
> Thanks for checking.  Does the following patch give dimensions of all
> physical monitors as in X11?  Do display-mm-height/width return
> meaningful values?

Sorry, can't apply the patch, `bzr patch' says 

bzr: ERROR: Error invoking patch: Invalid argument

If you resend it in unified format, I can try to apply it manually.

Without the patch, display-mm-height/width return some values, same on
both monitors, but I can't tell how they relate to x-display-*
functions.

ELISP> (x-display-pixel-height)
1200
ELISP> (x-display-pixel-width)
1920
ELISP> (display-mm-height)
423
ELISP> (display-mm-width)
677



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-20  0:12       ` Dmitry Gutov
@ 2013-03-20  0:20         ` YAMAMOTO Mitsuharu
  2013-03-20  1:41           ` Dmitry Gutov
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-20  0:20 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

>>>>> On Wed, 20 Mar 2013 04:12:58 +0400, Dmitry Gutov <dgutov@yandex.ru> said:

>> Thanks for checking.  Does the following patch give dimensions of
>> all physical monitors as in X11?  Do display-mm-height/width return
>> meaningful values?

> Sorry, can't apply the patch, `bzr patch' says

> bzr: ERROR: Error invoking patch: Invalid argument

> If you resend it in unified format, I can try to apply it manually.

You can convert the format from context diff to unified diff using C-c
C-u in diff-mode.  Anyway, I resend the patch.

> Without the patch, display-mm-height/width return some values, same
> on both monitors, but I can't tell how they relate to x-display-*
> functions.

Please also try display-mm-height/width after applying the patch.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'src/w32fns.c'
--- src/w32fns.c	2013-03-10 22:55:25 +0000
+++ src/w32fns.c	2013-03-19 23:47:14 +0000
@@ -4732,15 +4732,10 @@
 If omitted or nil, that stands for the selected frame's display.  */)
   (Lisp_Object display)
 {
-  struct w32_display_info *dpyinfo = check_x_display_info (display);
-  HDC hdc;
-  int cap;
-
-  hdc = GetDC (dpyinfo->root_window);
+  HDC hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
+  int cap = GetDeviceCaps (hdc, VERTSIZE);
 
-  cap = GetDeviceCaps (hdc, VERTSIZE);
-
-  ReleaseDC (dpyinfo->root_window, hdc);
+  DeleteDC (hdc);
 
   return make_number (cap);
 }
@@ -4752,16 +4747,10 @@
 If omitted or nil, that stands for the selected frame's display.  */)
   (Lisp_Object display)
 {
-  struct w32_display_info *dpyinfo = check_x_display_info (display);
-
-  HDC hdc;
-  int cap;
-
-  hdc = GetDC (dpyinfo->root_window);
-
-  cap = GetDeviceCaps (hdc, HORZSIZE);
+  HDC hdc = CreateDC ("DISPLAY", NULL, NULL, NULL);
+  int cap = GetDeviceCaps (hdc, HORZSIZE);
 
-  ReleaseDC (dpyinfo->root_window, hdc);
+  DeleteDC (hdc);
 
   return make_number (cap);
 }

=== modified file 'src/w32term.c'
--- src/w32term.c	2013-03-15 10:07:29 +0000
+++ src/w32term.c	2013-03-19 23:47:25 +0000
@@ -515,18 +515,18 @@
 int
 x_display_pixel_height (struct w32_display_info *dpyinfo)
 {
-  HDC dc = GetDC (NULL);
+  HDC dc = CreateDC ("DISPLAY", NULL, NULL, NULL);
   int pixels = GetDeviceCaps (dc, VERTRES);
-  ReleaseDC (NULL, dc);
+  DeleteDC (dc);
   return pixels;
 }
 
 int
 x_display_pixel_width (struct w32_display_info *dpyinfo)
 {
-  HDC dc = GetDC (NULL);
+  HDC dc = CreateDC ("DISPLAY", NULL, NULL, NULL);
   int pixels = GetDeviceCaps (dc, HORZRES);
-  ReleaseDC (NULL, dc);
+  DeleteDC (dc);
   return pixels;
 }
 




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-19 15:58         ` Drew Adams
@ 2013-03-20  0:55           ` Leo Liu
  0 siblings, 0 replies; 97+ messages in thread
From: Leo Liu @ 2013-03-20  0:55 UTC (permalink / raw)
  To: Drew Adams; +Cc: emacs-devel

On 2013-03-19 23:58 +0800, Drew Adams wrote:
> And? How is that relevant? What is the behavior you seek?

Set up the geometry in elisp. For example, after disconnecting from the
main large monitor, fit-frame-to-screen will resize my emacs to fit
current screen. I use this function all the time between my laptop and
external monitor. It has been a great help for my productivity. But my
cli tool only works on OSX.

We need the dimension of the screen not the combination of them. After
all 'maximize' doesn't maximize to cover all screens.

Leo



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-20  0:20         ` YAMAMOTO Mitsuharu
@ 2013-03-20  1:41           ` Dmitry Gutov
  2013-03-20  3:58             ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Dmitry Gutov @ 2013-03-20  1:41 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

>>>>>> On Wed, 20 Mar 2013 04:12:58 +0400, Dmitry Gutov <dgutov@yandex.ru> said:
>
>>> Thanks for checking.  Does the following patch give dimensions of
>>> all physical monitors as in X11?  Do display-mm-height/width return
>>> meaningful values?
>
>> Sorry, can't apply the patch, `bzr patch' says
>
>> bzr: ERROR: Error invoking patch: Invalid argument
>
>> If you resend it in unified format, I can try to apply it manually.
>
> You can convert the format from context diff to unified diff using C-c
> C-u in diff-mode.  Anyway, I resend the patch.

Indeed, I forgot about diff-mode. It can also apply the patch just fine.

>> Without the patch, display-mm-height/width return some values, same
>> on both monitors, but I can't tell how they relate to x-display-*
>> functions.
>
> Please also try display-mm-height/width after applying the patch.

Applied, compiled, and it doesn't seem to make any difference. Same
values, on both monitors. I'll repeat the experiment just in case, and
will follow-up if there's anything different.



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-20  1:41           ` Dmitry Gutov
@ 2013-03-20  3:58             ` YAMAMOTO Mitsuharu
  2013-03-20 14:05               ` Dmitry Gutov
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-20  3:58 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

>>>>> On Wed, 20 Mar 2013 05:41:19 +0400, Dmitry Gutov <dgutov@yandex.ru> said:

>>> Without the patch, display-mm-height/width return some values,
>>> same on both monitors, but I can't tell how they relate to
>>> x-display-* functions.
>> 
>> Please also try display-mm-height/width after applying the patch.

> Applied, compiled, and it doesn't seem to make any difference. Same
> values, on both monitors. I'll repeat the experiment just in case,
> and will follow-up if there's anything different.

What happens if you replace `CreateDC ("DISPLAY", NULL, NULL, NULL)'
in the patch with `CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL)' ?

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-20  3:58             ` YAMAMOTO Mitsuharu
@ 2013-03-20 14:05               ` Dmitry Gutov
  2013-03-20 23:28                 ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Dmitry Gutov @ 2013-03-20 14:05 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

>>>>>> On Wed, 20 Mar 2013 05:41:19 +0400, Dmitry Gutov <dgutov@yandex.ru> said:
>
>>>> Without the patch, display-mm-height/width return some values,
>>>> same on both monitors, but I can't tell how they relate to
>>>> x-display-* functions.
>>> 
>>> Please also try display-mm-height/width after applying the patch.
>
>> Applied, compiled, and it doesn't seem to make any difference. Same
>> values, on both monitors. I'll repeat the experiment just in case,
>> and will follow-up if there's anything different.
>
> What happens if you replace `CreateDC ("DISPLAY", NULL, NULL, NULL)'
> in the patch with `CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL)' ?

That doesn't seem to change anything, either.



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-20 14:05               ` Dmitry Gutov
@ 2013-03-20 23:28                 ` YAMAMOTO Mitsuharu
  2013-03-21  1:27                   ` Dmitry Gutov
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-20 23:28 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

>>>>> On Wed, 20 Mar 2013 18:05:10 +0400, Dmitry Gutov <dgutov@yandex.ru> said:

>> What happens if you replace `CreateDC ("DISPLAY", NULL, NULL,
>> NULL)' in the patch with `CreateDC (TEXT ("DISPLAY"), NULL, NULL,
>> NULL)' ?

> That doesn't seem to change anything, either.

Hmm, what about the following one?

And could someone who is familiar with the W32 (or NS) port help us
make these functions consistent with the X11 version?  Otherwise elisp
programs that use these common functions (unconsciously) relying on
platform-specific behavior will not work as intended on other
platforms.

(Actually, some users have sent me "bug reports" that the behavior of
display-pixel-width/height on the Mac port is "wrong" for the reason
that they do not return the same values as the NS port, whereas those
in the Mac port behave consistently with those in X11.)

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'src/w32fns.c'
--- src/w32fns.c	2013-03-20 11:29:37 +0000
+++ src/w32fns.c	2013-03-20 23:19:20 +0000
@@ -4733,11 +4733,11 @@
   HDC hdc;
   int cap;
 
-  hdc = GetDC (dpyinfo->root_window);
+  hdc = GUI_FN (CreateDC) (GUISTR ("DISPLAY"), NULL, NULL, NULL);
 
   cap = GetDeviceCaps (hdc, VERTSIZE);
 
-  ReleaseDC (dpyinfo->root_window, hdc);
+  DeleteDC (hdc);
 
   return make_number (cap);
 }
@@ -4754,11 +4754,11 @@
   HDC hdc;
   int cap;
 
-  hdc = GetDC (dpyinfo->root_window);
+  hdc = GUI_FN (CreateDC) (GUISTR ("DISPLAY"), NULL, NULL, NULL);
 
   cap = GetDeviceCaps (hdc, HORZSIZE);
 
-  ReleaseDC (dpyinfo->root_window, hdc);
+  DeleteDC (hdc);
 
   return make_number (cap);
 }

=== modified file 'src/w32term.c'
--- src/w32term.c	2013-03-15 10:07:29 +0000
+++ src/w32term.c	2013-03-20 23:10:16 +0000
@@ -515,18 +515,18 @@
 int
 x_display_pixel_height (struct w32_display_info *dpyinfo)
 {
-  HDC dc = GetDC (NULL);
+  HDC dc = GUI_FN (CreateDC) (GUISTR ("DISPLAY"), NULL, NULL, NULL);
   int pixels = GetDeviceCaps (dc, VERTRES);
-  ReleaseDC (NULL, dc);
+  DeleteDC (dc);
   return pixels;
 }
 
 int
 x_display_pixel_width (struct w32_display_info *dpyinfo)
 {
-  HDC dc = GetDC (NULL);
+  HDC dc = GUI_FN (CreateDC) (GUISTR ("DISPLAY"), NULL, NULL, NULL);
   int pixels = GetDeviceCaps (dc, HORZRES);
-  ReleaseDC (NULL, dc);
+  DeleteDC (dc);
   return pixels;
 }
 




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

* Re: x-display-pixel-width/height inconsistency
@ 2013-03-21  0:58 grischka
  2013-03-21  1:05 ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: grischka @ 2013-03-21  0:58 UTC (permalink / raw)
  To: mituharu; +Cc: emacs-devel

The DC has nothing to do with monitors because monitors are just
different coordinates on the same (virtual) screen. (Obviously
since you can drag the window between monitors, even such that
it's partially on two monitors at the same time.)

To get the the size of the monitor where your window is (mostly)
on you can use:

     MONITORINFO mi;
     HMONITOR hMon;
     RECT s;

     hmon = MonitorFromWindow(your_hwnd, MONITOR_DEFAULTTONEAREST);
     mi.cbSize = sizeof(mi);
     if (GetMonitorInfoA(hMon, &mi)) {
         s = mi.rcMonitor;  // entire screen, or
         s = mi.rcWork; // without taskbar
     }

--- gr



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  0:58 x-display-pixel-width/height inconsistency grischka
@ 2013-03-21  1:05 ` YAMAMOTO Mitsuharu
  2013-03-21  1:09   ` grischka
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-21  1:05 UTC (permalink / raw)
  To: grischka; +Cc: emacs-devel

>>>>> On Thu, 21 Mar 2013 01:58:38 +0100, grischka <grishka@gmx.de> said:

> The DC has nothing to do with monitors because monitors are just
> different coordinates on the same (virtual) screen. (Obviously since
> you can drag the window between monitors, even such that it's
> partially on two monitors at the same time.)

It is the size of whole "(virtual) screen" that we want to know here,
rather than the size of a particular monitor.  I tried to use CreateDC
because the reference says:

  If there are multiple monitors on the system, calling
  CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL) will create a DC covering
  all the monitors.
  http://msdn.microsoft.com/ja-jp/library/dd183490.aspx

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  1:05 ` YAMAMOTO Mitsuharu
@ 2013-03-21  1:09   ` grischka
  2013-03-21  1:44     ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: grischka @ 2013-03-21  1:09 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

YAMAMOTO Mitsuharu wrote:
>>>>>> On Thu, 21 Mar 2013 01:58:38 +0100, grischka <grishka@gmx.de> said:
> 
>> The DC has nothing to do with monitors because monitors are just
>> different coordinates on the same (virtual) screen. (Obviously since
>> you can drag the window between monitors, even such that it's
>> partially on two monitors at the same time.)
> 
> It is the size of whole "(virtual) screen" that we want to know here,
> rather than the size of a particular monitor.  

Then use
         w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
         h = GetSystemMetrics(SM_CYVIRTUALSCREEN);

--- gr

> I tried to use CreateDC
> because the reference says:
> 
>   If there are multiple monitors on the system, calling
>   CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL) will create a DC covering
>   all the monitors.
>   http://msdn.microsoft.com/ja-jp/library/dd183490.aspx
> 
> 				     YAMAMOTO Mitsuharu
> 				mituharu@math.s.chiba-u.ac.jp
> 




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-20 23:28                 ` YAMAMOTO Mitsuharu
@ 2013-03-21  1:27                   ` Dmitry Gutov
  2013-03-21  1:51                     ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Dmitry Gutov @ 2013-03-21  1:27 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> writes:

>>>>>> On Wed, 20 Mar 2013 18:05:10 +0400, Dmitry Gutov <dgutov@yandex.ru> said:
>
>>> What happens if you replace `CreateDC ("DISPLAY", NULL, NULL,
>>> NULL)' in the patch with `CreateDC (TEXT ("DISPLAY"), NULL, NULL,
>>> NULL)' ?
>
>> That doesn't seem to change anything, either.
>
> Hmm, what about the following one?

Still the same.

> And could someone who is familiar with the W32 (or NS) port help us
> make these functions consistent with the X11 version?  Otherwise elisp
> programs that use these common functions (unconsciously) relying on
> platform-specific behavior will not work as intended on other
> platforms.
>
> (Actually, some users have sent me "bug reports" that the behavior of
> display-pixel-width/height on the Mac port is "wrong" for the reason
> that they do not return the same values as the NS port, whereas those
> in the Mac port behave consistently with those in X11.)

Aside from it being X11 behavior, why do you consider it the "right"
one? I see how I could use one monitor's dimensions (to make Emacs take
full screen, or half width, etc), but what use is the "total size"?

My monitors are of different size, you couldn't make Emacs fully
maximized to both of them, even if you tried.



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  1:09   ` grischka
@ 2013-03-21  1:44     ` YAMAMOTO Mitsuharu
  2013-03-21 23:29       ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-21  1:44 UTC (permalink / raw)
  To: grischka; +Cc: emacs-devel

>>>>> On Thu, 21 Mar 2013 02:09:53 +0100, grischka <grishka@gmx.de> said:

>> It is the size of whole "(virtual) screen" that we want to know here,
>> rather than the size of a particular monitor.  

> Then use
>          w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
>          h = GetSystemMetrics(SM_CYVIRTUALSCREEN);

Thanks.  I tried making a patch using them.  Do you happen to know an
appropriate way to exclude Windows 95 and NT 4 where
SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not available?

			     YAMAMOTO Mitsuharu
			mituharu@math.s.chiba-u.ac.jp

=== modified file 'src/w32fns.c'
--- src/w32fns.c	2013-03-20 11:29:37 +0000
+++ src/w32fns.c	2013-03-21 01:39:22 +0000
@@ -4731,15 +4731,13 @@
 {
   struct w32_display_info *dpyinfo = check_x_display_info (display);
   HDC hdc;
-  int cap;
+  float ratio;
 
-  hdc = GetDC (dpyinfo->root_window);
+  hdc = GetDC (NULL);
+  ratio = (float) GetDeviceCaps (hdc, VERTSIZE) / GetDeviceCaps (dc, VERTRES);
+  ReleaseDC (NULL, hdc);
 
-  cap = GetDeviceCaps (hdc, VERTSIZE);
-
-  ReleaseDC (dpyinfo->root_window, hdc);
-
-  return make_number (cap);
+  return make_number ((int) (ratio * x_display_pixel_height (dpyinfo) + 0.5));
 }
 
 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
@@ -4750,17 +4748,14 @@
   (Lisp_Object display)
 {
   struct w32_display_info *dpyinfo = check_x_display_info (display);
-
   HDC hdc;
-  int cap;
-
-  hdc = GetDC (dpyinfo->root_window);
-
-  cap = GetDeviceCaps (hdc, HORZSIZE);
+  float ratio;
 
-  ReleaseDC (dpyinfo->root_window, hdc);
+  hdc = GetDC (NULL);
+  ratio = (float) GetDeviceCaps (hdc, HORZSIZE) / GetDeviceCaps (dc, HORZRES);
+  ReleaseDC (NULL, hdc);
 
-  return make_number (cap);
+  return make_number ((int) (ratio * x_display_pixel_width (dpyinfo) + 0.5));
 }
 
 DEFUN ("x-display-backing-store", Fx_display_backing_store,

=== modified file 'src/w32term.c'
--- src/w32term.c	2013-03-15 10:07:29 +0000
+++ src/w32term.c	2013-03-21 01:32:55 +0000
@@ -142,6 +142,15 @@
 #define WS_EX_LAYERED 0x80000
 #endif
 
+/* SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not defined on 95 and
+   NT4.  */
+#ifndef SM_CXVIRTUALSCREEN
+#define SM_CXVIRTUALSCREEN 78
+#endif
+#ifndef SM_CYVIRTUALSCREEN
+#define SM_CXVIRTUALSCREEN 79
+#endif
+
 /* This is a frame waiting to be autoraised, within w32_read_socket.  */
 struct frame *pending_autoraise_frame;
 
@@ -515,19 +524,29 @@
 int
 x_display_pixel_height (struct w32_display_info *dpyinfo)
 {
-  HDC dc = GetDC (NULL);
-  int pixels = GetDeviceCaps (dc, VERTRES);
-  ReleaseDC (NULL, dc);
-  return pixels;
+  if (1 /* XXX: exclude 95 and NT4 */)
+    return GetSystemMetrics (SM_CYVIRTUALSCREEN);
+  else
+    {
+      HDC dc = GetDC (NULL);
+      int pixels = GetDeviceCaps (dc, VERTRES);
+      ReleaseDC (NULL, dc);
+      return pixels;
+    }
 }
 
 int
 x_display_pixel_width (struct w32_display_info *dpyinfo)
 {
-  HDC dc = GetDC (NULL);
-  int pixels = GetDeviceCaps (dc, HORZRES);
-  ReleaseDC (NULL, dc);
-  return pixels;
+  if (1 /* XXX: exclude 95 and NT4 */)
+    return GetSystemMetrics (SM_CXVIRTUALSCREEN);
+  else
+    {
+      HDC dc = GetDC (NULL);
+      int pixels = GetDeviceCaps (dc, HORZRES);
+      ReleaseDC (NULL, dc);
+      return pixels;
+    }
 }
 
 \f




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  1:27                   ` Dmitry Gutov
@ 2013-03-21  1:51                     ` YAMAMOTO Mitsuharu
  2013-03-21  2:43                       ` Dmitry Gutov
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-21  1:51 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

>>>>> On Thu, 21 Mar 2013 05:27:42 +0400, Dmitry Gutov <dgutov@yandex.ru> said:

>> And could someone who is familiar with the W32 (or NS) port help us
>> make these functions consistent with the X11 version?  Otherwise elisp
>> programs that use these common functions (unconsciously) relying on
>> platform-specific behavior will not work as intended on other
>> platforms.
>> 
>> (Actually, some users have sent me "bug reports" that the behavior of
>> display-pixel-width/height on the Mac port is "wrong" for the reason
>> that they do not return the same values as the NS port, whereas those
>> in the Mac port behave consistently with those in X11.)

> Aside from it being X11 behavior, why do you consider it the "right"
> one? I see how I could use one monitor's dimensions (to make Emacs take
> full screen, or half width, etc), but what use is the "total size"?

> My monitors are of different size, you couldn't make Emacs fully
> maximized to both of them, even if you tried.

First, thanks for many experiments.

I understand users want to know the size of each monitor rather than
the total size.  But that does not justify changing existing common
functions in an inconsistent and ad hoc way and making them
platform-specific unnecessarily.  If such functionality is necessary,
it should be provided in a platform-independent and consistent way.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  1:51                     ` YAMAMOTO Mitsuharu
@ 2013-03-21  2:43                       ` Dmitry Gutov
  2013-03-21  3:47                         ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Dmitry Gutov @ 2013-03-21  2:43 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

On 21.03.2013 5:51, YAMAMOTO Mitsuharu wrote:
> First, thanks for many experiments.

No problem. Your latest patch has two typos:

w32fns.c: In function `Fx_display_mm_height':
w32fns.c:4737: error: `dc' undeclared (first use in this function)
w32fns.c:4737: error: (Each undeclared identifier is reported only once
w32fns.c:4737: error: for each function it appears in.)
w32fns.c: In function `Fx_display_mm_width':
w32fns.c:4755: error: `dc' undeclared (first use in this function)

With them fixed, the behavior seems to be right:

ELISP> (x-display-pixel-height)
1200
ELISP> (x-display-pixel-width)
3200
ELISP> (display-mm-height)
423
ELISP> (display-mm-width)
1128

That's the correct values for the bounding box. At least, the first two.

> I understand users want to know the size of each monitor rather than
> the total size.  But that does not justify changing existing common
> functions in an inconsistent and ad hoc way and making them
> platform-specific unnecessarily.  If such functionality is necessary,
> it should be provided in a platform-independent and consistent way.

Of course. I was just asking why you picked this specific behavior to 
make consistent across platforms.

If the existing X11 behavior is actually in use somewhere, then that 
makes sense, of course.



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  2:43                       ` Dmitry Gutov
@ 2013-03-21  3:47                         ` YAMAMOTO Mitsuharu
  2013-03-21  4:22                           ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-21  3:47 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

>>>>> On Thu, 21 Mar 2013 06:43:28 +0400, Dmitry Gutov <dgutov@yandex.ru> said:

> With them fixed, the behavior seems to be right:

ELISP> (x-display-pixel-height)
> 1200
ELISP> (x-display-pixel-width)
> 3200
ELISP> (display-mm-height)
> 423
ELISP> (display-mm-width)
> 1128

> That's the correct values for the bounding box. At least, the first
> two.

Thanks again for testing.

>> I understand users want to know the size of each monitor rather
>> than the total size.  But that does not justify changing existing
>> common functions in an inconsistent and ad hoc way and making them
>> platform-specific unnecessarily.  If such functionality is
>> necessary, it should be provided in a platform-independent and
>> consistent way.

> Of course. I was just asking why you picked this specific behavior
> to make consistent across platforms.

> If the existing X11 behavior is actually in use somewhere, then that
> makes sense, of course.

Other behavior is also OK with me as long as it is consistent across
platforms.  But I think the X11 behavior is the most natural (I won't
say useful) choice at this moment for the following reasons.

First, the behavior is documented in the info including the case for
multi-monitor setups.  Second, the other x-display-* functions query
properties per "display" (in the X11 terminology) determined by the
given argument.  Note that neither of "display" nor "screen" in the
X11 terminology has something to do with physical monitors (in this
sense, the implementation of x-display-screens in the NS port,
counting the number of physical monitors, is also wrong).  Third, I
guess distinguishing physical monitors on X11 requires the Xinerama
extension or some help of window managers.  So such functionality
seems to be at a different level from other x-display-* functions.

One may want to query not only the size of a particular physical
monitor but also the position and the displayable area (i.e., except
Panel, Dock, or Taskbar).  I think it would be better to provide the
functions that are aware of physical monitors as a new group of them,
rather than by breaking the existing argument convention of
x-display-* functions.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  3:47                         ` YAMAMOTO Mitsuharu
@ 2013-03-21  4:22                           ` YAMAMOTO Mitsuharu
  0 siblings, 0 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-21  4:22 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: emacs-devel

>>>>> On Thu, 21 Mar 2013 12:47:02 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

> Third, I guess distinguishing physical monitors on X11 requires the
> Xinerama extension or some help of window managers.  So such
> functionality seems to be at a different level from other
> x-display-* functions.

GDK might be an alternative choice when using GTK+.

> One may want to query not only the size of a particular physical
> monitor but also the position and the displayable area (i.e., except
> Panel, Dock, or Taskbar).  I think it would be better to provide the
> functions that are aware of physical monitors as a new group of
> them, rather than by breaking the existing argument convention of
> x-display-* functions.

And gdk_screen_*_monitor* could be a candidate of a design guide for
such a new group of functions.

  gint   gdk_screen_get_n_monitors           (GdkScreen *screen);
  gint   gdk_screen_get_primary_monitor      (GdkScreen *screen);
  void   gdk_screen_get_monitor_geometry     (GdkScreen *screen,
	 				      gint monitor_num,
	 				      GdkRectangle *dest);
  void   gdk_screen_get_monitor_workarea     (GdkScreen *screen,
	 				      gint monitor_num,
	 				      GdkRectangle *dest);
  gint   gdk_screen_get_monitor_at_point     (GdkScreen *screen,
	 				      gint x,
	 				      gint y);
  gint   gdk_screen_get_monitor_at_window    (GdkScreen *screen,
	 				      GdkWindow *window);
  gint   gdk_screen_get_monitor_height_mm    (GdkScreen *screen,
	 				      gint monitor_num);
  gint   gdk_screen_get_monitor_width_mm     (GdkScreen *screen,
	 				      gint monitor_num);
  gchar *gdk_screen_get_monitor_plug_name    (GdkScreen *screen,
					      gint monitor_num);

  https://developer.gnome.org/gdk3/3.6/GdkScreen.html

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21  1:44     ` YAMAMOTO Mitsuharu
@ 2013-03-21 23:29       ` YAMAMOTO Mitsuharu
  2013-03-22 10:33         ` Eli Zaretskii
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-21 23:29 UTC (permalink / raw)
  To: emacs-devel

>>>>> On Thu, 21 Mar 2013 10:44:29 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

>> Then use
>> w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
>> h = GetSystemMetrics(SM_CYVIRTUALSCREEN);

> Thanks.  I tried making a patch using them.  Do you happen to know an
> appropriate way to exclude Windows 95 and NT 4 where
> SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not available?

Patch updated.  I used the condition (w32_major_version == 4 &&
w32_minor_version == 0) to distinguish Windows 95 and NT 4 from the
other versions.  Also, changes for the NS port are included.

I'll install it in a few days if no problems found.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'src/nsfns.m'
*** src/nsfns.m	2013-03-20 09:56:19 +0000
--- src/nsfns.m	2013-03-21 23:16:54 +0000
***************
*** 144,187 ****
  }
  
  
! /* Let the user specify an Nextstep display with a frame.
!    nil stands for the selected frame--or, if that is not an Nextstep frame,
     the first Nextstep display on the list.  */
  static struct ns_display_info *
! check_ns_display_info (Lisp_Object frame)
  {
!   if (NILP (frame))
      {
!       struct frame *f = SELECTED_FRAME ();
!       if (FRAME_NS_P (f) && FRAME_LIVE_P (f) )
!         return FRAME_NS_DISPLAY_INFO (f);
        else if (x_display_list != 0)
!         return x_display_list;
        else
          error ("Nextstep windows are not in use or not initialized");
      }
!   else if (INTEGERP (frame))
      {
!       struct terminal *t = get_terminal (frame, 1);
  
        if (t->type != output_ns)
!         error ("Terminal %"pI"d is not a Nextstep display", XINT (frame));
  
!       return t->display_info.ns;
      }
!   else if (STRINGP (frame))
!     return ns_display_info_for_name (frame);
    else
      {
!       FRAME_PTR f;
! 
!       CHECK_LIVE_FRAME (frame);
!       f = XFRAME (frame);
!       if (! FRAME_NS_P (f))
!         error ("non-Nextstep frame used");
!       return FRAME_NS_DISPLAY_INFO (f);
      }
!   return NULL;  /* shut compiler up */
  }
  
  
--- 144,188 ----
  }
  
  
! /* Let the user specify a Nextstep display with a Lisp object.
!    OBJECT may be nil, a frame or a terminal object.
!    nil stands for the selected frame--or, if that is not a Nextstep frame,
     the first Nextstep display on the list.  */
+ 
  static struct ns_display_info *
! check_ns_display_info (Lisp_Object object)
  {
!   struct ns_display_info *dpyinfo = NULL;
! 
!   if (NILP (object))
      {
!       struct frame *sf = XFRAME (selected_frame);
! 
!       if (FRAME_NS_P (sf) && FRAME_LIVE_P (sf))
! 	dpyinfo = FRAME_NS_DISPLAY_INFO (sf);
        else if (x_display_list != 0)
! 	dpyinfo = x_display_list;
        else
          error ("Nextstep windows are not in use or not initialized");
      }
!   else if (TERMINALP (object))
      {
!       struct terminal *t = get_terminal (object, 1);
  
        if (t->type != output_ns)
!         error ("Terminal %"pI"d is not a Nextstep display", XINT (object));
  
!       dpyinfo = t->display_info.ns;
      }
!   else if (STRINGP (object))
!     dpyinfo = ns_display_info_for_name (object);
    else
      {
!       FRAME_PTR f = check_ns_frame (object);
!       dpyinfo = FRAME_NS_DISPLAY_INFO (f);
      }
! 
!   return dpyinfo;
  }
  
  
***************
*** 1699,1727 ****
  }
  
  
! DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height,
!        0, 1, 0,
!        doc: /* Return the height of Nextstep display server DISPLAY, in millimeters.
! DISPLAY should be a frame, the display name as a string, or a terminal ID.
! If omitted or nil, the selected frame's display is used.  */)
!      (Lisp_Object display)
  {
!   check_ns ();
!   return make_number ((int)
!                      ([ns_get_screen (display) frame].size.height/(92.0/25.4)));
  }
  
  
! DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width,
!        0, 1, 0,
!        doc: /* Return the width of Nextstep display server DISPLAY, in millimeters.
! DISPLAY should be a frame, the display name as a string, or a terminal ID.
! If omitted or nil, the selected frame's display is used.  */)
!      (Lisp_Object display)
  {
!   check_ns ();
!   return make_number ((int)
!                      ([ns_get_screen (display) frame].size.width/(92.0/25.4)));
  }
  
  
--- 1700,1728 ----
  }
  
  
! DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
!        doc: /* Return the height in millimeters of the Nextstep display TERMINAL.
! The optional argument TERMINAL specifies which display to ask about.
! TERMINAL should be a terminal object, a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
!   (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
! 
!   return make_number ((int) (x_display_pixel_height (dpyinfo) / (92.0/25.4)));
  }
  
  
! DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
!        doc: /* Return the width in millimeters of the Nextstep display TERMINAL.
! The optional argument TERMINAL specifies which display to ask about.
! TERMINAL should be a terminal object, a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
!   (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
! 
!   return make_number ((int) (x_display_pixel_width (dpyinfo) / (92.0/25.4)));
  }
  
  
***************
*** 1751,1766 ****
  
  DEFUN ("x-display-visual-class", Fx_display_visual_class,
         Sx_display_visual_class, 0, 1, 0,
!        doc: /* Return the visual class of the Nextstep display server DISPLAY.
  The value is one of the symbols `static-gray', `gray-scale',
  `static-color', `pseudo-color', `true-color', or `direct-color'.
! DISPLAY should be a frame, the display name as a string, or a terminal ID.
! If omitted or nil, the selected frame's display is used.  */)
!      (Lisp_Object display)
  {
!   NSWindowDepth depth;
!   check_ns ();
!   depth = [ns_get_screen (display) depth];
  
    if ( depth == NSBestDepth (NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
      return intern ("static-gray");
--- 1752,1768 ----
  
  DEFUN ("x-display-visual-class", Fx_display_visual_class,
         Sx_display_visual_class, 0, 1, 0,
!        doc: /* Return the visual class of the Nextstep display TERMINAL.
  The value is one of the symbols `static-gray', `gray-scale',
  `static-color', `pseudo-color', `true-color', or `direct-color'.
! 
! The optional argument TERMINAL specifies which display to ask about.
! TERMINAL should a terminal object, a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
!   (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
!   NSWindowDepth depth = [[[NSScreen screens] objectAtIndex:0] depth];
  
    if ( depth == NSBestDepth (NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
      return intern ("static-gray");
***************
*** 2332,2344 ****
  
  DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
         doc: /* Internal function called by `display-color-p', which see.  */)
!      (Lisp_Object display)
  {
!   NSWindowDepth depth;
!   NSString *colorSpace;
!   check_ns ();
!   depth = [ns_get_screen (display) depth];
!   colorSpace = NSColorSpaceFromDepth (depth);
  
    return    [colorSpace isEqualToString: NSDeviceWhiteColorSpace]
           || [colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
--- 2334,2344 ----
  
  DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
         doc: /* Internal function called by `display-color-p', which see.  */)
!      (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
!   NSWindowDepth depth = [[[NSScreen screens] objectAtIndex:0] depth];
!   NSString *colorSpace = NSColorSpaceFromDepth (depth);
  
    return    [colorSpace isEqualToString: NSDeviceWhiteColorSpace]
           || [colorSpace isEqualToString: NSCalibratedWhiteColorSpace]
***************
*** 2346,2363 ****
  }
  
  
! DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
!        Sx_display_grayscale_p, 0, 1, 0,
         doc: /* Return t if the Nextstep display supports shades of gray.
  Note that color displays do support shades of gray.
! The optional argument DISPLAY specifies which display to ask about.
! DISPLAY should be either a frame, a display name (a string), or terminal ID.
! If omitted or nil, that stands for the selected frame's display. */)
!      (Lisp_Object display)
  {
!   NSWindowDepth depth;
!   check_ns ();
!   depth = [ns_get_screen (display) depth];
  
    return NSBitsPerPixelFromDepth (depth) > 1 ? Qt : Qnil;
  }
--- 2346,2362 ----
  }
  
  
! DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
!        0, 1, 0,
         doc: /* Return t if the Nextstep display supports shades of gray.
  Note that color displays do support shades of gray.
! The optional argument TERMINAL specifies which display to ask about.
! TERMINAL should be a terminal object, a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
!   (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
!   NSWindowDepth depth = [[[NSScreen screens] objectAtIndex:0] depth];
  
    return NSBitsPerPixelFromDepth (depth) > 1 ? Qt : Qnil;
  }
***************
*** 2365,2391 ****
  
  DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
         0, 1, 0,
!        doc: /* Return the width in pixels of the Nextstep display DISPLAY.
! The optional argument DISPLAY specifies which display to ask about.
! DISPLAY should be either a frame, a display name (a string), or terminal ID.
  If omitted or nil, that stands for the selected frame's display.  */)
!      (Lisp_Object display)
  {
!   check_ns ();
!   return make_number ((int) [ns_get_screen (display) frame].size.width);
  }
  
  
  DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
         Sx_display_pixel_height, 0, 1, 0,
!        doc: /* Return the height in pixels of the Nextstep display DISPLAY.
! The optional argument DISPLAY specifies which display to ask about.
! DISPLAY should be either a frame, a display name (a string), or terminal ID.
  If omitted or nil, that stands for the selected frame's display.  */)
!      (Lisp_Object display)
  {
!   check_ns ();
!   return make_number ((int) [ns_get_screen (display) frame].size.height);
  }
  
  
--- 2364,2392 ----
  
  DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
         0, 1, 0,
!        doc: /* Return the width in pixels of the Nextstep display TERMINAL.
! The optional argument TERMINAL specifies which display to ask about.
! TERMINAL should be a terminal object, a frame or a display name (a string).
  If omitted or nil, that stands for the selected frame's display.  */)
!   (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
! 
!   return make_number (x_display_pixel_width (dpyinfo));
  }
  
  
  DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
         Sx_display_pixel_height, 0, 1, 0,
!        doc: /* Return the height in pixels of the Nextstep display TERMINAL.
! The optional argument TERMINAL specifies which display to ask about.
! TERMINAL should be a terminal object, a frame or a display name (a string).
  If omitted or nil, that stands for the selected frame's display.  */)
!   (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
! 
!   return make_number (x_display_pixel_height (dpyinfo));
  }
  
  
***************
*** 2422,2436 ****
  
  DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
         0, 1, 0,
!        doc: /* Return the number of bitplanes of the Nextstep display DISPLAY.
! The optional argument DISPLAY specifies which display to ask about.
! DISPLAY should be either a frame, a display name (a string), or terminal ID.
  If omitted or nil, that stands for the selected frame's display.  */)
!      (Lisp_Object display)
  {
!   check_ns ();
    return make_number
!     (NSBitsPerPixelFromDepth ([ns_get_screen (display) depth]));
  }
  
  
--- 2423,2438 ----
  
  DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
         0, 1, 0,
!        doc: /* Return the number of bitplanes of the Nextstep display TERMINAL.
! The optional argument TERMINAL specifies which display to ask about.
! TERMINAL should be a terminal object, a frame or a display name (a string).
  If omitted or nil, that stands for the selected frame's display.  */)
!   (Lisp_Object terminal)
  {
!   struct ns_display_info *dpyinfo = check_ns_display_info (terminal);
! 
    return make_number
!     (NSBitsPerPixelFromDepth ([[[NSScreen screens] objectAtIndex:0] depth]));
  }
  
  

=== modified file 'src/nsterm.m'
*** src/nsterm.m	2013-03-16 14:22:37 +0000
--- src/nsterm.m	2013-03-21 22:55:46 +0000
***************
*** 3813,3827 ****
  int
  x_display_pixel_height (struct ns_display_info *dpyinfo)
  {
!   NSScreen *screen = [NSScreen mainScreen];
!   return [screen frame].size.height;
  }
  
  int
  x_display_pixel_width (struct ns_display_info *dpyinfo)
  {
!   NSScreen *screen = [NSScreen mainScreen];
!   return [screen frame].size.width;
  }
  
  
--- 3813,3843 ----
  int
  x_display_pixel_height (struct ns_display_info *dpyinfo)
  {
!   NSArray *screens = [NSScreen screens];
!   NSEnumerator *enumerator = [screens objectEnumerator];
!   NSScreen *screen;
!   NSRect frame;
! 
!   frame = NSZeroRect;
!   while ((screen = [enumerator nextObject]) != nil)
!     frame = NSUnionRect (frame, [screen frame]);
! 
!   return NSHeight (frame);
  }
  
  int
  x_display_pixel_width (struct ns_display_info *dpyinfo)
  {
!   NSArray *screens = [NSScreen screens];
!   NSEnumerator *enumerator = [screens objectEnumerator];
!   NSScreen *screen;
!   NSRect frame;
! 
!   frame = NSZeroRect;
!   while ((screen = [enumerator nextObject]) != nil)
!     frame = NSUnionRect (frame, [screen frame]);
! 
!   return NSWidth (frame);
  }
  
  

=== modified file 'src/w32fns.c'
*** src/w32fns.c	2013-03-20 11:29:37 +0000
--- src/w32fns.c	2013-03-21 05:20:04 +0000
***************
*** 4731,4745 ****
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   int cap;
  
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, VERTSIZE);
! 
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
--- 4731,4745 ----
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   float mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((float) GetDeviceCaps (hdc, VERTSIZE)
! 		  / GetDeviceCaps (hdc, VERTRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number ((int) (x_display_pixel_height (dpyinfo) * mm_per_pixel
! 			     + 0.5f));
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
***************
*** 4750,4766 ****
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
- 
    HDC hdc;
!   int cap;
! 
!   hdc = GetDC (dpyinfo->root_window);
! 
!   cap = GetDeviceCaps (hdc, HORZSIZE);
  
!   ReleaseDC (dpyinfo->root_window, hdc);
  
!   return make_number (cap);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
--- 4750,4765 ----
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   float mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((float) GetDeviceCaps (hdc, HORZSIZE)
! 		  / GetDeviceCaps (hdc, HORZRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number ((int) (x_display_pixel_width (dpyinfo) * mm_per_pixel
! 			     + 0.5f));
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,

=== modified file 'src/w32term.c'
*** src/w32term.c	2013-03-15 10:07:29 +0000
--- src/w32term.c	2013-03-21 05:08:16 +0000
***************
*** 142,147 ****
--- 142,156 ----
  #define WS_EX_LAYERED 0x80000
  #endif
  
+ /* SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not defined on 95 and
+    NT4.  */
+ #ifndef SM_CXVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 78
+ #endif
+ #ifndef SM_CYVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 79
+ #endif
+ 
  /* This is a frame waiting to be autoraised, within w32_read_socket.  */
  struct frame *pending_autoraise_frame;
  
***************
*** 515,533 ****
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, VERTRES);
!   ReleaseDC (NULL, dc);
!   return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, HORZRES);
!   ReleaseDC (NULL, dc);
!   return pixels;
  }
  
  \f
--- 524,554 ----
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   if (!(w32_major_version == 4 && w32_minor_version == 0))
!     return GetSystemMetrics (SM_CYVIRTUALSCREEN);
!   else
!     {
!       /* Windows 95 or NT 4.0 */
!       HDC dc = GetDC (NULL);
!       int pixels = GetDeviceCaps (dc, VERTRES);
!       ReleaseDC (NULL, dc);
!       return pixels;
!     }
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   if (!(w32_major_version == 4 && w32_minor_version == 0))
!     return GetSystemMetrics (SM_CXVIRTUALSCREEN);
!   else
!     {
!       /* Windows 95 or NT 4.0 */
!       HDC dc = GetDC (NULL);
!       int pixels = GetDeviceCaps (dc, HORZRES);
!       ReleaseDC (NULL, dc);
!       return pixels;
!     }
  }
  
  \f




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-21 23:29       ` YAMAMOTO Mitsuharu
@ 2013-03-22 10:33         ` Eli Zaretskii
  2013-03-23  0:32           ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Eli Zaretskii @ 2013-03-22 10:33 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Fri, 22 Mar 2013 08:29:55 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> 
> >>>>> On Thu, 21 Mar 2013 10:44:29 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:
> 
> >> Then use
> >> w = GetSystemMetrics(SM_CXVIRTUALSCREEN);
> >> h = GetSystemMetrics(SM_CYVIRTUALSCREEN);
> 
> > Thanks.  I tried making a patch using them.  Do you happen to know an
> > appropriate way to exclude Windows 95 and NT 4 where
> > SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not available?
> 
> Patch updated.  I used the condition (w32_major_version == 4 &&
> w32_minor_version == 0) to distinguish Windows 95 and NT 4 from the
> other versions.

How did you deduce that SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are
not available on those old systems?  Can you point me to some
documentation which has the details?

If we do need to distinguish those systems, there's os_subtype
variable, which can help you be sure that you include both Windows 9X
and NT 4.0, as version info on 9X is somewhat tricky.

> --- 4731,4745 ----
>   {
>     struct w32_display_info *dpyinfo = check_x_display_info (display);
>     HDC hdc;
> !   float mm_per_pixel;
>   
> !   hdc = GetDC (NULL);
> !   mm_per_pixel = ((float) GetDeviceCaps (hdc, VERTSIZE)
> ! 		  / GetDeviceCaps (hdc, VERTRES));
> !   ReleaseDC (NULL, hdc);
>   
> !   return make_number ((int) (x_display_pixel_height (dpyinfo) * mm_per_pixel
> ! 			     + 0.5f));
>   }
>   
>   DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,

I'm bothered by the fact that you change the behavior of these
functions in backward-incompatible ways, without properly documenting
what values they return.  The new doc strings do not add _anything_ to
the vagueness of the previous description wrt what exactly are the
"display dimensions".  Now, you may be right about what these
primitives do on X11 (I don't know enough about that to tell, and the
man pages I've seen are not helpful), but if so, we should clearly
document their semantics, either in the doc strings or/and in the
ELisp manual.  We certainly should mention the change in behavior in
NEWS.

Personally, I am still unsure how will dimensions of "the bounding
rectangle of all display monitors" be helpful to any Lisp program; can
you tell why you think returning that is a good idea?  Maybe we
should change the X11 implementation instead?



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-22 10:33         ` Eli Zaretskii
@ 2013-03-23  0:32           ` YAMAMOTO Mitsuharu
  2013-03-23  6:15             ` Eli Zaretskii
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-23  0:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Fri, 22 Mar 2013 12:33:36 +0200, Eli Zaretskii <eliz@gnu.org> said:

> How did you deduce that SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN
> are not available on those old systems?  Can you point me to some
> documentation which has the details?

http://msdn.microsoft.com/ja-jp/library/cc429812.aspx
(in Japanese.  But probably you can find "Window 98" and "Windows
2000" around SM_CXVIRTUALSCREEN/SM_CYVIRTUALSCREEN)

I couldn't find a corresponding document in English.

> If we do need to distinguish those systems, there's os_subtype
> variable, which can help you be sure that you include both Windows
> 9X and NT 4.0, as version info on 9X is somewhat tricky.

I think it is enough to distinguish Windows 95 and Windows NT 4.0 from
the other versions, and both 95 and NT4 seem to have the same major
and minor versions (4 and 0) maybe by accident, while they have
different os_subtype values.  (Correct me if wrong.)

> I'm bothered by the fact that you change the behavior of these
> functions in backward-incompatible ways, without properly
> documenting what values they return.  The new doc strings do not add
> _anything_ to the vagueness of the previous description wrt what
> exactly are the "display dimensions".  Now, you may be right about
> what these primitives do on X11 (I don't know enough about that to
> tell, and the man pages I've seen are not helpful), but if so, we
> should clearly document their semantics, either in the doc strings
> or/and in the ELisp manual.  We certainly should mention the change
> in behavior in NEWS.

As I've already mentioned, the elisp info already contains the
description about the semantics under multi-monitor setups.

  http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00469.html

Probably we can copy it to the doc strings if necessary.  Previously
only the info was updated by a maintainer (see the thread starting
from http://lists.gnu.org/archive/html/emacs-devel/2007-04/msg00400.html).

> Personally, I am still unsure how will dimensions of "the bounding
> rectangle of all display monitors" be helpful to any Lisp program;
> can you tell why you think returning that is a good idea?  Maybe we
> should change the X11 implementation instead?

Please look at my other posts:

  http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00553.html
  http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00555.html

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-23  0:32           ` YAMAMOTO Mitsuharu
@ 2013-03-23  6:15             ` Eli Zaretskii
  2013-03-23 13:35               ` Jan Djärv
  2013-03-23 23:58               ` YAMAMOTO Mitsuharu
  0 siblings, 2 replies; 97+ messages in thread
From: Eli Zaretskii @ 2013-03-23  6:15 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Sat, 23 Mar 2013 09:32:31 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> >>>>> On Fri, 22 Mar 2013 12:33:36 +0200, Eli Zaretskii <eliz@gnu.org> said:
> 
> > How did you deduce that SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN
> > are not available on those old systems?  Can you point me to some
> > documentation which has the details?
> 
> http://msdn.microsoft.com/ja-jp/library/cc429812.aspx
> (in Japanese.  But probably you can find "Window 98" and "Windows
> 2000" around SM_CXVIRTUALSCREEN/SM_CYVIRTUALSCREEN)

Does it say something like "Starting from Windows 98 and Windows
2000"?  That's what I get from other sources on the Internet that talk
about this subject.

> > If we do need to distinguish those systems, there's os_subtype
> > variable, which can help you be sure that you include both Windows
> > 9X and NT 4.0, as version info on 9X is somewhat tricky.
> 
> I think it is enough to distinguish Windows 95 and Windows NT 4.0 from
> the other versions, and both 95 and NT4 seem to have the same major
> and minor versions (4 and 0) maybe by accident, while they have
> different os_subtype values.  (Correct me if wrong.)

I actually think we should always call GetSystemMetrics, and if that
returns a failure indication, call the old code.  Testing versions is
usually less desirable.

> > I'm bothered by the fact that you change the behavior of these
> > functions in backward-incompatible ways, without properly
> > documenting what values they return.  The new doc strings do not add
> > _anything_ to the vagueness of the previous description wrt what
> > exactly are the "display dimensions".  Now, you may be right about
> > what these primitives do on X11 (I don't know enough about that to
> > tell, and the man pages I've seen are not helpful), but if so, we
> > should clearly document their semantics, either in the doc strings
> > or/and in the ELisp manual.  We certainly should mention the change
> > in behavior in NEWS.
> 
> As I've already mentioned, the elisp info already contains the
> description about the semantics under multi-monitor setups.
> 
>   http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00469.html

That talks about display-pixel-width/height, while I was talking about
x-display-pixel-width/height, the primitives where you propose the
changes.  The latter are not mentioned in the ELisp manual at all, so
their doc strings are the only source of documentation for them.

Moreover, your changes touch x-display-mm-width/height as well, so now
display-mm-width/height, whose documentation in the ELisp manual
doesn't mention multiple terminals at all, will behave differently as
well.

> > Personally, I am still unsure how will dimensions of "the bounding
> > rectangle of all display monitors" be helpful to any Lisp program;
> > can you tell why you think returning that is a good idea?  Maybe we
> > should change the X11 implementation instead?
> 
> Please look at my other posts:
> 
>   http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00553.html
>   http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00555.html

I've read all the thread, and I'm still asking the question, because
nothing there seems to provide the answer.  Maybe you should re-read
my question.

What you say in those messages boils down to

  . the X11 behavior is documented in the manual

  . Emacs on X11 cannot distinguish between physical monitors that
    belong to the same display

As I write above, the first point is only partially true
(display-mm-width/height are not documented as describing the virtual
screen, and the x-display-* primitives are not documented at all).  As
for the second point, I don't see how it can be any guideline to make
a decision, since both NS and W32 _can_ distinguish between physical
monitors (if we include the appropriate code).

So the question still stands: which behavior should be considered
"correct" and which a "missing feature".



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-23  6:15             ` Eli Zaretskii
@ 2013-03-23 13:35               ` Jan Djärv
  2013-03-23 23:58               ` YAMAMOTO Mitsuharu
  1 sibling, 0 replies; 97+ messages in thread
From: Jan Djärv @ 2013-03-23 13:35 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: YAMAMOTO Mitsuharu, emacs-devel@gnu.org

Hello. 


23 mar 2013 kl. 07:15 skrev Eli Zaretskii <eliz@gnu.org>:

> 
> What you say in those messages boils down to
> 
>  . the X11 behavior is documented in the manual
> 
>  . Emacs on X11 cannot distinguish between physical monitors that
>    belong to the same display
> 
> As I write above, the first point is only partially true
> (display-mm-width/height are not documented as describing the virtual
> screen, and the x-display-* primitives are not documented at all).  As
> for the second point, I don't see how it can be any guideline to make
> a decision, since both NS and W32 _can_ distinguish between physical
> monitors (if we include the appropriate code).
> 
> So the question still stands: which behavior should be considered
> "correct" and which a "missing feature".

I guess the X11 port was coded before multiple monitors was common. When it was discovered that the primitives used returned the whole combined size, that behaviour was documented. I doubt there was any well thought out reason for having it like it is. Well, finding monitor sizes was probably hard to impossible.

But that is hardly a reason to keep it as it is. We can do better now.

    Jan D.




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

* Re: x-display-pixel-width/height inconsistency
  2013-03-23  6:15             ` Eli Zaretskii
  2013-03-23 13:35               ` Jan Djärv
@ 2013-03-23 23:58               ` YAMAMOTO Mitsuharu
  2013-03-24  3:53                 ` Eli Zaretskii
  1 sibling, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-23 23:58 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Sat, 23 Mar 2013 08:15:03 +0200, Eli Zaretskii <eliz@gnu.org> said:

>> > How did you deduce that SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN
>> > are not available on those old systems?  Can you point me to some
>> > documentation which has the details?
>> 
>> http://msdn.microsoft.com/ja-jp/library/cc429812.aspx (in Japanese.
>> But probably you can find "Window 98" and "Windows 2000" around
>> SM_CXVIRTUALSCREEN/SM_CYVIRTUALSCREEN)

> Does it say something like "Starting from Windows 98 and Windows
> 2000"?  That's what I get from other sources on the Internet that
> talk about this subject.

It says "Window 98 AND Windows 2000".  Probably because this document
was written before XP or Me.

> I actually think we should always call GetSystemMetrics, and if that
> returns a failure indication, call the old code.  Testing versions
> is usually less desirable.

Could you check GetSystemMetrics safely returns 0 for unknown
arguments (because I can't test it)?  If so, avoiding version tests
would be better.

>> As I've already mentioned, the elisp info already contains the
>> description about the semantics under multi-monitor setups.
>> 
>> http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00469.html

> That talks about display-pixel-width/height, while I was talking
> about x-display-pixel-width/height, the primitives where you propose
> the changes.  The latter are not mentioned in the ELisp manual at
> all, so their doc strings are the only source of documentation for
> them.

> Moreover, your changes touch x-display-mm-width/height as well, so
> now display-mm-width/height, whose documentation in the ELisp manual
> doesn't mention multiple terminals at all, will behave differently
> as well.

If these functions behave differently among the platforms on
multi-monitor setups, then they should be named with different
prefixes (i.e., w32-display-*, ns-display-*.  Note that the current
behavior is different even between W32 and NS).  Of course, I prefer
consistent behavior rather than having the different prefix.

>> Please look at my other posts:
>> 
>> http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00553.html
>> http://lists.gnu.org/archive/html/emacs-devel/2013-03/msg00555.html

> I've read all the thread, and I'm still asking the question, because
> nothing there seems to provide the answer.  Maybe you should re-read
> my question.

> What you say in those messages boils down to

>   . the X11 behavior is documented in the manual

>   . Emacs on X11 cannot distinguish between physical monitors that
> belong to the same display

> As I write above, the first point is only partially true
> (display-mm-width/height are not documented as describing the
> virtual screen, and the x-display-* primitives are not documented at
> all).  As for the second point, I don't see how it can be any
> guideline to make a decision, since both NS and W32 _can_
> distinguish between physical monitors (if we include the appropriate
> code).

> So the question still stands: which behavior should be considered
> "correct" and which a "missing feature".

My whole point is that functions for obtaining properties of each
physical monitor on multi-monitor setups should be provided as a new
function (or a new group of functions), rather than abusing the
existing functions x-display-* on displays primarily designed after
the notion of X11 "display" or "screen".  Users would want to know
several kinds of information about each monitor, such as the geometry
(including the origin) or the workarea, not just about size in pixels.
Tweeking x-display-pixel-width/height in a platform-specific way or
adding functions such as display-usable-bounds in the NS port without
considering the whole design for operations on monitors looks rather
ad hoc to me.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-23 23:58               ` YAMAMOTO Mitsuharu
@ 2013-03-24  3:53                 ` Eli Zaretskii
  2013-03-24  4:36                   ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Eli Zaretskii @ 2013-03-24  3:53 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Sun, 24 Mar 2013 08:58:29 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> > I actually think we should always call GetSystemMetrics, and if that
> > returns a failure indication, call the old code.  Testing versions
> > is usually less desirable.
> 
> Could you check GetSystemMetrics safely returns 0 for unknown
> arguments (because I can't test it)?

What else can it do?  Failing for invalid parameters is what Windows
APIs always do.

> > Moreover, your changes touch x-display-mm-width/height as well, so
> > now display-mm-width/height, whose documentation in the ELisp manual
> > doesn't mention multiple terminals at all, will behave differently
> > as well.
> 
> If these functions behave differently among the platforms on
> multi-monitor setups, then they should be named with different
> prefixes (i.e., w32-display-*, ns-display-*.  Note that the current
> behavior is different even between W32 and NS).  Of course, I prefer
> consistent behavior rather than having the different prefix.

That's a different issue.  My point was that your patch should include
changes to doc strings that describe what these functions will do
after the changes are installed.

As for different names, it depends on what we decide to be the
"normative" behavior.

> My whole point is that functions for obtaining properties of each
> physical monitor on multi-monitor setups should be provided as a new
> function (or a new group of functions), rather than abusing the
> existing functions x-display-* on displays primarily designed after
> the notion of X11 "display" or "screen".

No one said that "display" refers to all the monitors on the X11
display.  It could be just a coincidence, since these functions were
written when each X11 display had only one monitor.  And as for
"screen", that term does not appear in the functions' names or in
their doc strings (which talk about "terminal").

> Users would want to know
> several kinds of information about each monitor, such as the geometry
> (including the origin) or the workarea, not just about size in pixels.

The problem of geometry and the origin exists for a single virtual
display as well.

> Tweeking x-display-pixel-width/height in a platform-specific way or
> adding functions such as display-usable-bounds in the NS port without
> considering the whole design for operations on monitors looks rather
> ad hoc to me.

Then please present a design that would make sense, not just an ad-hoc
set of changes to align all the platforms to the X11 behavior.



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-24  3:53                 ` Eli Zaretskii
@ 2013-03-24  4:36                   ` YAMAMOTO Mitsuharu
  2013-03-24 16:19                     ` Eli Zaretskii
  2013-04-27  5:13                     ` YAMAMOTO Mitsuharu
  0 siblings, 2 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-03-24  4:36 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Sun, 24 Mar 2013 05:53:10 +0200, Eli Zaretskii <eliz@gnu.org> said:

>> Could you check GetSystemMetrics safely returns 0 for unknown
>> arguments (because I can't test it)?

> What else can it do?  Failing for invalid parameters is what Windows
> APIs always do.

I'm not a W32 expert.  So I thought the possibility of aborting (as a
fatal program bug) or writing warning messages to some syslog
counterparts for invalid parameters.

> That's a different issue.  My point was that your patch should
> include changes to doc strings that describe what these functions
> will do after the changes are installed.

> As for different names, it depends on what we decide to be the
> "normative" behavior.

OK.  My proposal is to determine that the term "display" in Emacs
refers to the notion of that in X11 (the whole screen spanning
possibly multiple all the physical monitors) so that we can define
"normative" behaviors the functions (x-)display-*.  Very simple and no
change required for X11.

As we currently have three different behaviors of
(x-)display-pixel-width/height on different platforms, whatever we
define the "normative" behavior, at least two of them must be changed
if we try to make them consistent across the platforms.

> No one said that "display" refers to all the monitors on the X11
> display.  It could be just a coincidence, since these functions were
> written when each X11 display had only one monitor.  And as for
> "screen", that term does not appear in the functions' names or in
> their doc strings (which talk about "terminal").

Documentations could be updated accordingly once we determine the
"normative" behavior as above.

>> Users would want to know several kinds of information about each
>> monitor, such as the geometry (including the origin) or the
>> workarea, not just about size in pixels.
> The problem of geometry and the origin exists for a single virtual
> display as well.

??? Could you expand?

>> Tweeking x-display-pixel-width/height in a platform-specific way or
>> adding functions such as display-usable-bounds in the NS port
>> without considering the whole design for operations on monitors
>> looks rather ad hoc to me.

> Then please present a design that would make sense, not just an
> ad-hoc set of changes to align all the platforms to the X11
> behavior.

Aligning all the platforms to the X11 is not ad hoc but makes several
things consistent, not only behaviors among multiple platforms but
also the argument convention among x-display-* functions.

A possible design for the new function would be:

DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list, Sx_display_monitor_attributes_list,
       0, 1, 0,
       doc: /* Return a list of physical monitor attributes on X display.

Each element of the list represents the attributes of each physical
monitor.  The first element corresponds to the primary monitor.

Attributes for a physical monitor is represented as an alist of
attribute names and values as follows:

    Name      | Value
    ----------|------------------------------------
    geometry  | position and size
              | of the form (LEFT TOP WIDTH HEIGHT)
    work-area | position and size of the work area
              | of the form (LEFT TOP WIDTH HEIGHT)
    mm-size   | width and height in millimeters
              | of the form (WIDTH HEIGHT)

where LEFT TOP WIDTH, and HEIGHT are integers.

The optional argument TERMINAL specifies which display to ask about.
TERMINAL should be a terminal object, a frame or a display name (a string).
If omitted or nil, that stands for the selected frame's display.  */)
  (Lisp_Object terminal)

The attributes are selected from the GdkScreen monitor functions.
Some platform-specific attributes can also be included (if they are
only meaningful on the platform), e.g., backing scale factor on OSX.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-24  4:36                   ` YAMAMOTO Mitsuharu
@ 2013-03-24 16:19                     ` Eli Zaretskii
  2013-04-27  5:13                     ` YAMAMOTO Mitsuharu
  1 sibling, 0 replies; 97+ messages in thread
From: Eli Zaretskii @ 2013-03-24 16:19 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Sun, 24 Mar 2013 13:36:03 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> >>>>> On Sun, 24 Mar 2013 05:53:10 +0200, Eli Zaretskii <eliz@gnu.org> said:
> 
> >> Could you check GetSystemMetrics safely returns 0 for unknown
> >> arguments (because I can't test it)?
> 
> > What else can it do?  Failing for invalid parameters is what Windows
> > APIs always do.
> 
> I'm not a W32 expert.  So I thought the possibility of aborting (as a
> fatal program bug) or writing warning messages to some syslog
> counterparts for invalid parameters.

The "normal" (i.e., non-buggy) behavior of the Windows APIs is to
return an error indication and set the error code (returned by
GetLastError) to ERROR_INVALID_PARAMETER.  I don't have access to NT 4
or Windows 95, but I verified that on XP passing 200 as the parameter
indeed yields this behavior for GetSystemMetrics.

> > That's a different issue.  My point was that your patch should
> > include changes to doc strings that describe what these functions
> > will do after the changes are installed.
> 
> > As for different names, it depends on what we decide to be the
> > "normative" behavior.
> 
> OK.  My proposal is to determine that the term "display" in Emacs
> refers to the notion of that in X11 (the whole screen spanning
> possibly multiple all the physical monitors) so that we can define
> "normative" behaviors the functions (x-)display-*.  Very simple and no
> change required for X11.

Please include the necessary documentation changes to codify this
behavior, and then I have no objections to such a change.

> Documentations could be updated accordingly once we determine the
> "normative" behavior as above.

I think documentation changes should be part of the proposed changes
in this case.

> >> Users would want to know several kinds of information about each
> >> monitor, such as the geometry (including the origin) or the
> >> workarea, not just about size in pixels.
> > The problem of geometry and the origin exists for a single virtual
> > display as well.
> 
> ??? Could you expand?

See this page, for example:

   http://msdn.microsoft.com/en-us/library/windows/desktop/dd145136%28v=vs.85%29.aspx

As you see, the origin is on the top-left corner of the _primary_
monitor, and if some other monitor is configured to display the
portion of the virtual screen to the left of the primary, the X
coordinates there will be negative.  What happens on X11 and NS in
this case?



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

* Re: x-display-pixel-width/height inconsistency
  2013-03-24  4:36                   ` YAMAMOTO Mitsuharu
  2013-03-24 16:19                     ` Eli Zaretskii
@ 2013-04-27  5:13                     ` YAMAMOTO Mitsuharu
  2013-04-27  8:04                       ` Jan Djärv
  2013-04-28  1:48                       ` YAMAMOTO Mitsuharu
  1 sibling, 2 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-04-27  5:13 UTC (permalink / raw)
  To: emacs-devel

>>>>> On Sun, 24 Mar 2013 13:36:03 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

>>> Tweeking x-display-pixel-width/height in a platform-specific way
>>> or adding functions such as display-usable-bounds in the NS port
>>> without considering the whole design for operations on monitors
>>> looks rather ad hoc to me.

>> Then please present a design that would make sense, not just an
>> ad-hoc set of changes to align all the platforms to the X11
>> behavior.

> Aligning all the platforms to the X11 is not ad hoc but makes
> several things consistent, not only behaviors among multiple
> platforms but also the argument convention among x-display-*
> functions.

> A possible design for the new function would be:

> DEFUN ("x-display-monitor-attributes-list",

The patch below implements this primitive for GTK+ builds (and also
contains a "degenerated" fallback for non-GTK+ X11 builds) as a
starting point for the discussion about its design.

What would the preferred format for rectangles be?  The patch uses the
format that geometry-related functions (such as x-parse-geometry) are
using, but it might look a bit awkward for this purpose because of
quoting "+" for possibly negative coordinates for positions.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'src/xfns.c'
*** src/xfns.c	2013-04-07 04:41:19 +0000
--- src/xfns.c	2013-04-26 13:58:27 +0000
***************
*** 126,131 ****
--- 126,132 ----
  static Lisp_Object Qsuppress_icon;
  static Lisp_Object Qundefined_color;
  static Lisp_Object Qcompound_text, Qcancel_timer;
+ static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes;
  Lisp_Object Qfont_param;
  
  #ifdef GLYPH_DEBUG
***************
*** 3791,3796 ****
--- 3792,4067 ----
    else
      return Qnil;
  }
+ 
+ /* Return an alist of the form
+    ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+     (width . WIDTH) (height . HEIGHT))
+    with converting XOFFSET, YOFFSET, WIDTH and HEIGHT to Lisp
+    integers.  */
+ 
+ static Lisp_Object
+ x_create_geometry_alist (EMACS_INT xoffset, EMACS_INT yoffset,
+ 			 EMACS_INT width, EMACS_INT height)
+ {
+   return list4 (Fcons (Qleft, list2 (Qplus, make_number (xoffset))),
+ 		Fcons (Qtop, list2 (Qplus, make_number (yoffset))),
+ 		Fcons (Qwidth, make_number (width)),
+ 		Fcons (Qheight, make_number (height)));
+ }
+ 
+ /* Return an alist of the form ((width . WIDTH) (height . HEIGHT)).
+    with converting WIDTH and HEIGHT to Lisp integers.  */
+ 
+ static Lisp_Object
+ x_create_size_alist (EMACS_INT width, EMACS_INT height)
+ {
+   return list2 (Fcons (Qwidth, make_number (width)),
+ 		Fcons (Qheight, make_number (height)));
+ }
+ 
+ /* Store the geometry of the workarea on display DPYINFO into *RECT.
+    Return false if and only if the workarea information cannot be
+    obtained via the _NET_WORKAREA root window property.  */
+ 
+ static bool
+ x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect)
+ {
+   Display *dpy = dpyinfo->display;
+   long offset, max_len;
+   Atom target_type, actual_type;
+   unsigned long actual_size, bytes_remaining;
+   int rc, actual_format;
+   unsigned char *tmp_data = NULL;
+   bool result = false;
+ 
+   x_catch_errors (dpy);
+   offset = 0;
+   max_len = 1;
+   target_type = XA_CARDINAL;
+   rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+ 			   dpyinfo->Xatom_net_current_desktop,
+ 			   offset, max_len, False, target_type,
+ 			   &actual_type, &actual_format, &actual_size,
+ 			   &bytes_remaining, &tmp_data);
+   if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+       && actual_format == 32 && actual_size == max_len)
+     {
+       long current_desktop = ((long *) tmp_data)[0];
+ 
+       XFree (tmp_data);
+       tmp_data = NULL;
+ 
+       offset = 4 * current_desktop;
+       max_len = 4;
+       rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+ 			       dpyinfo->Xatom_net_workarea,
+ 			       offset, max_len, False, target_type,
+ 			       &actual_type, &actual_format, &actual_size,
+ 			       &bytes_remaining, &tmp_data);
+       if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+ 	  && actual_format == 32 && actual_size == max_len)
+ 	{
+ 	  long *workareas = (long *) tmp_data;
+ 
+ 	  rect->x = workareas[0];
+ 	  rect->y = workareas[1];
+ 	  rect->width = workareas[2];
+ 	  rect->height = workareas[3];
+ 
+ 	  XFree (tmp_data);
+ 	  tmp_data = NULL;
+ 
+ 	  result = true;
+ 	}
+     }
+   if (tmp_data)
+     XFree (tmp_data);
+   x_uncatch_errors ();
+ 
+   return result;
+ }
+ 
+ DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
+        Sx_display_monitor_attributes_list,
+        0, 1, 0,
+        doc: /* Return a list of physical monitor attributes on X display.
+ Each element of the list represents the attributes of each physical
+ monitor.  The first element corresponds to the primary monitor.
+ 
+ Attributes for a physical monitor is represented as an alist of
+ attribute names and values as follows:
+ 
+     Name     | Value
+     ---------+--------------------------------------------------
+     geometry | Position and size in the form of
+ 	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+ 	     |  (width . WIDTH) (height . HEIGHT)).
+ 	     |
+     workarea | Position and size of the workarea in the form of
+ 	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+ 	     |  (width . WIDTH) (height . HEIGHT)).
+ 	     |
+     mm-size  | Width and height in millimeters in the form of
+ 	     | ((width . WIDTH) (height . HEIGHT)).
+ 	     |
+     frames   | List of frames belonging to the physical monitor.
+ 
+ where XOFFSET, YOFFSET, WIDTH, and HEIGHT are integers.  A frame
+ belongs to a monitor when either the largest area of the frame resides
+ in the monitor, or the monitor is the closest to the frame if the
+ frame does not intersect any monitors.  Every non-tip frame (including
+ invisible one) in a graphical display belongs to exactly one monitor.
+ 
+ The optional argument TERMINAL specifies which display to ask about.
+ TERMINAL should be a terminal object, a frame or a display name (a string).
+ If omitted or nil, that stands for the selected frame's display.  */)
+   (Lisp_Object terminal)
+ {
+   struct x_display_info *dpyinfo = check_x_display_info (terminal);
+   Lisp_Object attributes_list = Qnil, rest, frame;
+ 
+ #ifdef USE_GTK
+   float mm_width_per_pixel, mm_height_per_pixel;
+   GdkDisplay *gdpy;
+   GdkScreen *gscreen;
+   gint primary_monitor = 0, n_monitors, i;
+   Lisp_Object primary_monitor_attributes = Qnil;
+   Lisp_Object monitor_frames;
+ 
+   block_input ();
+   mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
+ 			/ x_display_pixel_width (dpyinfo));
+   mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
+ 			 / x_display_pixel_height (dpyinfo));
+   gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+   gscreen = gdk_display_get_default_screen (gdpy);
+ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 20
+   primary_monitor = gdk_screen_get_primary_monitor (gscreen);
+ #endif
+   n_monitors = gdk_screen_get_n_monitors (gscreen);
+   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	{
+ 	  GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+ 
+ 	  i = gdk_screen_get_monitor_at_window (gscreen, gwin);
+ 	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+ 	}
+     }
+ 
+   i = n_monitors;
+   while (i-- > 0)
+     {
+       Lisp_Object geometry, workarea, attributes = Qnil;
+       gint width_mm = -1, height_mm = -1;
+       GdkRectangle rec;
+ 
+       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+ 			  attributes);
+ 
+       gdk_screen_get_monitor_geometry (gscreen, i, &rec);
+       geometry = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
+ 
+ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 14
+       width_mm = gdk_screen_get_monitor_width_mm (gscreen, i);
+       height_mm = gdk_screen_get_monitor_height_mm (gscreen, i);
+ #endif
+       if (width_mm < 0)
+ 	width_mm = rec.width * mm_width_per_pixel + 0.5;
+       if (height_mm < 0)
+ 	height_mm = rec.height * mm_height_per_pixel + 0.5;
+       attributes = Fcons (Fcons (Qmm_size,
+ 				 x_create_size_alist (width_mm, height_mm)),
+ 			  attributes);
+ 
+ #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4)
+       gdk_screen_get_monitor_workarea (gscreen, i, &rec);
+       workarea = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
+ #else
+       /* Emulate the behavior of GTK+ 3.4.  */
+       {
+ 	XRectangle workarea_r;
+ 
+ 	workarea = Qnil;
+ 	if (i == primary_monitor && x_get_net_workarea (dpyinfo, &workarea_r))
+ 	  {
+ 	    GdkRectangle work;
+ 
+ 	    work.x = workarea_r.x;
+ 	    work.y = workarea_r.y;
+ 	    work.width = workarea_r.width;
+ 	    work.height = workarea_r.height;
+ 	    if (gdk_rectangle_intersect (&rec, &work, &work))
+ 	      workarea = x_create_geometry_alist (work.x, work.y,
+ 						  work.width, work.height);
+ 	  }
+ 	if (NILP (workarea))
+ 	  workarea = geometry;
+       }
+ #endif
+       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+       if (i == primary_monitor)
+ 	primary_monitor_attributes = attributes;
+       else
+ 	attributes_list = Fcons (attributes, attributes_list);
+     }
+ 
+   if (!NILP (primary_monitor_attributes))
+     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+   unblock_input ();
+ #else  /* not USE_GTK */
+   /* Fallback: treat (possibly) multiple physical monitors as if they
+      formed a single monitor as a whole.  This should provide a
+      consistent result at least on single monitor environments.  */
+   Lisp_Object geometry, workarea, frames, attributes = Qnil;
+   int width_mm, height_mm;
+   XRectangle workarea_r;
+ 
+   block_input ();
+   frames = Qnil;
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	frames = Fcons (frame, frames);
+     }
+   attributes = Fcons (Fcons (Qframes, frames), attributes);
+ 
+   width_mm = WidthMMOfScreen (dpyinfo->screen);
+   height_mm = HeightMMOfScreen (dpyinfo->screen);
+   attributes = Fcons (Fcons (Qmm_size,
+ 			     x_create_size_alist (width_mm, height_mm)),
+ 		      attributes);
+ 
+   geometry = x_create_geometry_alist (0, 0, x_display_pixel_width (dpyinfo),
+ 				      x_display_pixel_height (dpyinfo));
+ 
+   if (x_get_net_workarea (dpyinfo, &workarea_r))
+     workarea = x_create_geometry_alist (workarea_r.x, workarea_r.y,
+ 					workarea_r.width, workarea_r.height);
+   else
+     workarea = geometry;
+   attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+   attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+   attributes_list = list1 (attributes);
+   unblock_input ();
+ #endif	/* not USE_GTK */
+ 
+   return attributes_list;
+ }
+ 
  \f
  int
  x_pixel_width (register struct frame *f)
***************
*** 5701,5706 ****
--- 5972,5981 ----
    DEFSYM (Qundefined_color, "undefined-color");
    DEFSYM (Qcompound_text, "compound-text");
    DEFSYM (Qcancel_timer, "cancel-timer");
+   DEFSYM (Qgeometry, "geometry");
+   DEFSYM (Qworkarea, "workarea");
+   DEFSYM (Qmm_size, "mm-size");
+   DEFSYM (Qframes, "frames");
    DEFSYM (Qfont_param, "font-parameter");
    /* This is the end of symbol initialization.  */
  
***************
*** 5864,5869 ****
--- 6139,6145 ----
    defsubr (&Sx_display_visual_class);
    defsubr (&Sx_display_backing_store);
    defsubr (&Sx_display_save_under);
+   defsubr (&Sx_display_monitor_attributes_list);
    defsubr (&Sx_wm_set_size_hint);
    defsubr (&Sx_create_frame);
    defsubr (&Sx_open_connection);

=== modified file 'src/xterm.c'
*** src/xterm.c	2013-03-25 17:58:35 +0000
--- src/xterm.c	2013-04-26 00:15:04 +0000
***************
*** 10251,10256 ****
--- 10251,10258 ----
        { "_NET_WM_WINDOW_OPACITY", &dpyinfo->Xatom_net_wm_window_opacity },
        { "_NET_ACTIVE_WINDOW", &dpyinfo->Xatom_net_active_window },
        { "_NET_FRAME_EXTENTS", &dpyinfo->Xatom_net_frame_extents },
+       { "_NET_CURRENT_DESKTOP", &dpyinfo->Xatom_net_current_desktop },
+       { "_NET_WORKAREA", &dpyinfo->Xatom_net_workarea },
        /* Session management */
        { "SM_CLIENT_ID", &dpyinfo->Xatom_SM_CLIENT_ID },
        { "_XSETTINGS_SETTINGS", &dpyinfo->Xatom_xsettings_prop },

=== modified file 'src/xterm.h'
*** src/xterm.h	2013-04-07 04:41:19 +0000
--- src/xterm.h	2013-04-26 00:15:24 +0000
***************
*** 346,352 ****
    Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
      Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
      Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
!     Xatom_net_frame_extents;
  
    /* XSettings atoms and windows.  */
    Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
--- 346,353 ----
    Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
      Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
      Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
!     Xatom_net_frame_extents,
!     Xatom_net_current_desktop, Xatom_net_workarea;
  
    /* XSettings atoms and windows.  */
    Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;




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

* Re: x-display-pixel-width/height inconsistency
  2013-04-27  5:13                     ` YAMAMOTO Mitsuharu
@ 2013-04-27  8:04                       ` Jan Djärv
  2013-04-28  1:40                         ` YAMAMOTO Mitsuharu
  2013-04-28  1:48                       ` YAMAMOTO Mitsuharu
  1 sibling, 1 reply; 97+ messages in thread
From: Jan Djärv @ 2013-04-27  8:04 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

Hello.

A general objection is that XRandr/Xinerama is not used, so the non-Gtk+ code relies on a freedesktop compliant window manager, rather than taking the general approach.  If XRandr/Xinerama is used, no split between Gtk+ and non-Gtk+ code is needed.  Xrandr/Xinerama is what Gtk+ use anyway so we are not adding any new dependencies.

	Jan D.

27 apr 2013 kl. 07:13 skrev YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>:

>>>>>> On Sun, 24 Mar 2013 13:36:03 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:
> 
>>>> Tweeking x-display-pixel-width/height in a platform-specific way
>>>> or adding functions such as display-usable-bounds in the NS port
>>>> without considering the whole design for operations on monitors
>>>> looks rather ad hoc to me.
> 
>>> Then please present a design that would make sense, not just an
>>> ad-hoc set of changes to align all the platforms to the X11
>>> behavior.
> 
>> Aligning all the platforms to the X11 is not ad hoc but makes
>> several things consistent, not only behaviors among multiple
>> platforms but also the argument convention among x-display-*
>> functions.
> 
>> A possible design for the new function would be:
> 
>> DEFUN ("x-display-monitor-attributes-list",
> 
> The patch below implements this primitive for GTK+ builds (and also
> contains a "degenerated" fallback for non-GTK+ X11 builds) as a
> starting point for the discussion about its design.
> 
> What would the preferred format for rectangles be?  The patch uses the
> format that geometry-related functions (such as x-parse-geometry) are
> using, but it might look a bit awkward for this purpose because of
> quoting "+" for possibly negative coordinates for positions.
> 
> 				     YAMAMOTO Mitsuharu
> 				mituharu@math.s.chiba-u.ac.jp
> 
> === modified file 'src/xfns.c'
> *** src/xfns.c	2013-04-07 04:41:19 +0000
> --- src/xfns.c	2013-04-26 13:58:27 +0000
> ***************
> *** 126,131 ****
> --- 126,132 ----
>  static Lisp_Object Qsuppress_icon;
>  static Lisp_Object Qundefined_color;
>  static Lisp_Object Qcompound_text, Qcancel_timer;
> + static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes;
>  Lisp_Object Qfont_param;
> 
>  #ifdef GLYPH_DEBUG
> ***************
> *** 3791,3796 ****
> --- 3792,4067 ----
>    else
>      return Qnil;
>  }
> + 
> + /* Return an alist of the form
> +    ((left . (+ XOFFSET)) (top . (+ YOFFSET))
> +     (width . WIDTH) (height . HEIGHT))
> +    with converting XOFFSET, YOFFSET, WIDTH and HEIGHT to Lisp
> +    integers.  */
> + 
> + static Lisp_Object
> + x_create_geometry_alist (EMACS_INT xoffset, EMACS_INT yoffset,
> + 			 EMACS_INT width, EMACS_INT height)
> + {
> +   return list4 (Fcons (Qleft, list2 (Qplus, make_number (xoffset))),
> + 		Fcons (Qtop, list2 (Qplus, make_number (yoffset))),
> + 		Fcons (Qwidth, make_number (width)),
> + 		Fcons (Qheight, make_number (height)));
> + }
> + 
> + /* Return an alist of the form ((width . WIDTH) (height . HEIGHT)).
> +    with converting WIDTH and HEIGHT to Lisp integers.  */
> + 
> + static Lisp_Object
> + x_create_size_alist (EMACS_INT width, EMACS_INT height)
> + {
> +   return list2 (Fcons (Qwidth, make_number (width)),
> + 		Fcons (Qheight, make_number (height)));
> + }
> + 
> + /* Store the geometry of the workarea on display DPYINFO into *RECT.
> +    Return false if and only if the workarea information cannot be
> +    obtained via the _NET_WORKAREA root window property.  */
> + 
> + static bool
> + x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect)
> + {
> +   Display *dpy = dpyinfo->display;
> +   long offset, max_len;
> +   Atom target_type, actual_type;
> +   unsigned long actual_size, bytes_remaining;
> +   int rc, actual_format;
> +   unsigned char *tmp_data = NULL;
> +   bool result = false;
> + 
> +   x_catch_errors (dpy);
> +   offset = 0;
> +   max_len = 1;
> +   target_type = XA_CARDINAL;
> +   rc = XGetWindowProperty (dpy, dpyinfo->root_window,
> + 			   dpyinfo->Xatom_net_current_desktop,
> + 			   offset, max_len, False, target_type,
> + 			   &actual_type, &actual_format, &actual_size,
> + 			   &bytes_remaining, &tmp_data);
> +   if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
> +       && actual_format == 32 && actual_size == max_len)
> +     {
> +       long current_desktop = ((long *) tmp_data)[0];
> + 
> +       XFree (tmp_data);
> +       tmp_data = NULL;
> + 
> +       offset = 4 * current_desktop;
> +       max_len = 4;
> +       rc = XGetWindowProperty (dpy, dpyinfo->root_window,
> + 			       dpyinfo->Xatom_net_workarea,
> + 			       offset, max_len, False, target_type,
> + 			       &actual_type, &actual_format, &actual_size,
> + 			       &bytes_remaining, &tmp_data);
> +       if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
> + 	  && actual_format == 32 && actual_size == max_len)
> + 	{
> + 	  long *workareas = (long *) tmp_data;
> + 
> + 	  rect->x = workareas[0];
> + 	  rect->y = workareas[1];
> + 	  rect->width = workareas[2];
> + 	  rect->height = workareas[3];
> + 
> + 	  XFree (tmp_data);
> + 	  tmp_data = NULL;
> + 
> + 	  result = true;
> + 	}
> +     }
> +   if (tmp_data)
> +     XFree (tmp_data);
> +   x_uncatch_errors ();
> + 
> +   return result;
> + }
> + 
> + DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
> +        Sx_display_monitor_attributes_list,
> +        0, 1, 0,
> +        doc: /* Return a list of physical monitor attributes on X display.
> + Each element of the list represents the attributes of each physical
> + monitor.  The first element corresponds to the primary monitor.
> + 
> + Attributes for a physical monitor is represented as an alist of
> + attribute names and values as follows:
> + 
> +     Name     | Value
> +     ---------+--------------------------------------------------
> +     geometry | Position and size in the form of
> + 	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
> + 	     |  (width . WIDTH) (height . HEIGHT)).
> + 	     |
> +     workarea | Position and size of the workarea in the form of
> + 	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
> + 	     |  (width . WIDTH) (height . HEIGHT)).
> + 	     |
> +     mm-size  | Width and height in millimeters in the form of
> + 	     | ((width . WIDTH) (height . HEIGHT)).
> + 	     |
> +     frames   | List of frames belonging to the physical monitor.
> + 
> + where XOFFSET, YOFFSET, WIDTH, and HEIGHT are integers.  A frame
> + belongs to a monitor when either the largest area of the frame resides
> + in the monitor, or the monitor is the closest to the frame if the
> + frame does not intersect any monitors.  Every non-tip frame (including
> + invisible one) in a graphical display belongs to exactly one monitor.
> + 
> + The optional argument TERMINAL specifies which display to ask about.
> + TERMINAL should be a terminal object, a frame or a display name (a string).
> + If omitted or nil, that stands for the selected frame's display.  */)
> +   (Lisp_Object terminal)
> + {
> +   struct x_display_info *dpyinfo = check_x_display_info (terminal);
> +   Lisp_Object attributes_list = Qnil, rest, frame;
> + 
> + #ifdef USE_GTK
> +   float mm_width_per_pixel, mm_height_per_pixel;
> +   GdkDisplay *gdpy;
> +   GdkScreen *gscreen;
> +   gint primary_monitor = 0, n_monitors, i;
> +   Lisp_Object primary_monitor_attributes = Qnil;
> +   Lisp_Object monitor_frames;
> + 
> +   block_input ();
> +   mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
> + 			/ x_display_pixel_width (dpyinfo));
> +   mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
> + 			 / x_display_pixel_height (dpyinfo));
> +   gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
> +   gscreen = gdk_display_get_default_screen (gdpy);
> + #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 20
> +   primary_monitor = gdk_screen_get_primary_monitor (gscreen);
> + #endif
> +   n_monitors = gdk_screen_get_n_monitors (gscreen);
> +   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
> +   FOR_EACH_FRAME (rest, frame)
> +     {
> +       struct frame *f = XFRAME (frame);
> + 
> +       if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
> + 	  && !EQ (frame, tip_frame))
> + 	{
> + 	  GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
> + 
> + 	  i = gdk_screen_get_monitor_at_window (gscreen, gwin);
> + 	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
> + 	}
> +     }
> + 
> +   i = n_monitors;
> +   while (i-- > 0)
> +     {
> +       Lisp_Object geometry, workarea, attributes = Qnil;
> +       gint width_mm = -1, height_mm = -1;
> +       GdkRectangle rec;
> + 
> +       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
> + 			  attributes);
> + 
> +       gdk_screen_get_monitor_geometry (gscreen, i, &rec);
> +       geometry = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
> + 
> + #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 14
> +       width_mm = gdk_screen_get_monitor_width_mm (gscreen, i);
> +       height_mm = gdk_screen_get_monitor_height_mm (gscreen, i);
> + #endif
> +       if (width_mm < 0)
> + 	width_mm = rec.width * mm_width_per_pixel + 0.5;
> +       if (height_mm < 0)
> + 	height_mm = rec.height * mm_height_per_pixel + 0.5;
> +       attributes = Fcons (Fcons (Qmm_size,
> + 				 x_create_size_alist (width_mm, height_mm)),
> + 			  attributes);
> + 
> + #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4)
> +       gdk_screen_get_monitor_workarea (gscreen, i, &rec);
> +       workarea = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
> + #else
> +       /* Emulate the behavior of GTK+ 3.4.  */
> +       {
> + 	XRectangle workarea_r;
> + 
> + 	workarea = Qnil;
> + 	if (i == primary_monitor && x_get_net_workarea (dpyinfo, &workarea_r))
> + 	  {
> + 	    GdkRectangle work;
> + 
> + 	    work.x = workarea_r.x;
> + 	    work.y = workarea_r.y;
> + 	    work.width = workarea_r.width;
> + 	    work.height = workarea_r.height;
> + 	    if (gdk_rectangle_intersect (&rec, &work, &work))
> + 	      workarea = x_create_geometry_alist (work.x, work.y,
> + 						  work.width, work.height);
> + 	  }
> + 	if (NILP (workarea))
> + 	  workarea = geometry;
> +       }
> + #endif
> +       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
> + 
> +       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
> + 
> +       if (i == primary_monitor)
> + 	primary_monitor_attributes = attributes;
> +       else
> + 	attributes_list = Fcons (attributes, attributes_list);
> +     }
> + 
> +   if (!NILP (primary_monitor_attributes))
> +     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
> +   unblock_input ();
> + #else  /* not USE_GTK */
> +   /* Fallback: treat (possibly) multiple physical monitors as if they
> +      formed a single monitor as a whole.  This should provide a
> +      consistent result at least on single monitor environments.  */
> +   Lisp_Object geometry, workarea, frames, attributes = Qnil;
> +   int width_mm, height_mm;
> +   XRectangle workarea_r;
> + 
> +   block_input ();
> +   frames = Qnil;
> +   FOR_EACH_FRAME (rest, frame)
> +     {
> +       struct frame *f = XFRAME (frame);
> + 
> +       if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
> + 	  && !EQ (frame, tip_frame))
> + 	frames = Fcons (frame, frames);
> +     }
> +   attributes = Fcons (Fcons (Qframes, frames), attributes);
> + 
> +   width_mm = WidthMMOfScreen (dpyinfo->screen);
> +   height_mm = HeightMMOfScreen (dpyinfo->screen);
> +   attributes = Fcons (Fcons (Qmm_size,
> + 			     x_create_size_alist (width_mm, height_mm)),
> + 		      attributes);
> + 
> +   geometry = x_create_geometry_alist (0, 0, x_display_pixel_width (dpyinfo),
> + 				      x_display_pixel_height (dpyinfo));
> + 
> +   if (x_get_net_workarea (dpyinfo, &workarea_r))
> +     workarea = x_create_geometry_alist (workarea_r.x, workarea_r.y,
> + 					workarea_r.width, workarea_r.height);
> +   else
> +     workarea = geometry;
> +   attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
> + 
> +   attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
> + 
> +   attributes_list = list1 (attributes);
> +   unblock_input ();
> + #endif	/* not USE_GTK */
> + 
> +   return attributes_list;
> + }
> + 
>  \f
>  int
>  x_pixel_width (register struct frame *f)
> ***************
> *** 5701,5706 ****
> --- 5972,5981 ----
>    DEFSYM (Qundefined_color, "undefined-color");
>    DEFSYM (Qcompound_text, "compound-text");
>    DEFSYM (Qcancel_timer, "cancel-timer");
> +   DEFSYM (Qgeometry, "geometry");
> +   DEFSYM (Qworkarea, "workarea");
> +   DEFSYM (Qmm_size, "mm-size");
> +   DEFSYM (Qframes, "frames");
>    DEFSYM (Qfont_param, "font-parameter");
>    /* This is the end of symbol initialization.  */
> 
> ***************
> *** 5864,5869 ****
> --- 6139,6145 ----
>    defsubr (&Sx_display_visual_class);
>    defsubr (&Sx_display_backing_store);
>    defsubr (&Sx_display_save_under);
> +   defsubr (&Sx_display_monitor_attributes_list);
>    defsubr (&Sx_wm_set_size_hint);
>    defsubr (&Sx_create_frame);
>    defsubr (&Sx_open_connection);
> 
> === modified file 'src/xterm.c'
> *** src/xterm.c	2013-03-25 17:58:35 +0000
> --- src/xterm.c	2013-04-26 00:15:04 +0000
> ***************
> *** 10251,10256 ****
> --- 10251,10258 ----
>        { "_NET_WM_WINDOW_OPACITY", &dpyinfo->Xatom_net_wm_window_opacity },
>        { "_NET_ACTIVE_WINDOW", &dpyinfo->Xatom_net_active_window },
>        { "_NET_FRAME_EXTENTS", &dpyinfo->Xatom_net_frame_extents },
> +       { "_NET_CURRENT_DESKTOP", &dpyinfo->Xatom_net_current_desktop },
> +       { "_NET_WORKAREA", &dpyinfo->Xatom_net_workarea },
>        /* Session management */
>        { "SM_CLIENT_ID", &dpyinfo->Xatom_SM_CLIENT_ID },
>        { "_XSETTINGS_SETTINGS", &dpyinfo->Xatom_xsettings_prop },
> 
> === modified file 'src/xterm.h'
> *** src/xterm.h	2013-04-07 04:41:19 +0000
> --- src/xterm.h	2013-04-26 00:15:24 +0000
> ***************
> *** 346,352 ****
>    Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
>      Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
>      Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
> !     Xatom_net_frame_extents;
> 
>    /* XSettings atoms and windows.  */
>    Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
> --- 346,353 ----
>    Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
>      Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
>      Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
> !     Xatom_net_frame_extents,
> !     Xatom_net_current_desktop, Xatom_net_workarea;
> 
>    /* XSettings atoms and windows.  */
>    Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
> 




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

* Re: x-display-pixel-width/height inconsistency
  2013-04-27  8:04                       ` Jan Djärv
@ 2013-04-28  1:40                         ` YAMAMOTO Mitsuharu
  2013-04-28 17:16                           ` Jan D.
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-04-28  1:40 UTC (permalink / raw)
  To: Jan Djärv; +Cc: emacs-devel

>>>>> On Sat, 27 Apr 2013 10:04:46 +0200, Jan Djärv <jan.h.d@swipnet.se> said:

> A general objection is that XRandr/Xinerama is not used, so
> the non-Gtk+ code relies on a freedesktop compliant window manager,
> rather than taking the general approach.  If XRandr/Xinerama is
> used, no split between Gtk+ and non-Gtk+ code is needed.
> Xrandr/Xinerama is what Gtk+ use anyway so we are not adding any new
> dependencies.

Of course, patches welcome.  (And also for implementations for other
platforms.)  I guess XRandR 1.2 covers most of the current uses.

Because XRandR or Xinerama doesn't help us get information about the
workarea (that's the task of window managers), we need some function
like x_get_net_workarea regardless of the use of XRandR or Xinerama.

Even with XRandR or Xinerama code, leaving the GDK code would be
meaningful because we may have yet another framework for multiple
monitor support (GDK already covers 3 of them on X11) in future.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-04-27  5:13                     ` YAMAMOTO Mitsuharu
  2013-04-27  8:04                       ` Jan Djärv
@ 2013-04-28  1:48                       ` YAMAMOTO Mitsuharu
  1 sibling, 0 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-04-28  1:48 UTC (permalink / raw)
  To: emacs-devel

>>>>> On Sat, 27 Apr 2013 14:13:46 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

> What would the preferred format for rectangles be?  The patch uses
> the format that geometry-related functions (such as
> x-parse-geometry) are using, but it might look a bit awkward for
> this purpose because of quoting "+" for possibly negative
> coordinates for positions.

I adopted the geometry format `((left . (+ XOFFSET)) (top . (+
YOFFSET)) (width . WIDTH) (height . HEIGHT))' because I thought a
simple format like `(XOFFSET YOFFSET WIDTH HEIGHT)' might make Lisp
codes that use this primitive more cryptic (`caddr' or `nth 2' for
getting the WIDTH part).  On second thought, the `pcase' macro could
remedy this.  So the simple format might be better.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-04-28  1:40                         ` YAMAMOTO Mitsuharu
@ 2013-04-28 17:16                           ` Jan D.
  2013-04-29  2:27                             ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Jan D. @ 2013-04-28 17:16 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1587 bytes --]

Hello.

28 apr 2013 kl. 03:40 skrev YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>:

>>>>>> On Sat, 27 Apr 2013 10:04:46 +0200, Jan Djärv <jan.h.d@swipnet.se> said:
> 
>> A general objection is that XRandr/Xinerama is not used, so
>> the non-Gtk+ code relies on a freedesktop compliant window manager,
>> rather than taking the general approach.  If XRandr/Xinerama is
>> used, no split between Gtk+ and non-Gtk+ code is needed.
>> Xrandr/Xinerama is what Gtk+ use anyway so we are not adding any new
>> dependencies.
> 
> Of course, patches welcome.  (And also for implementations for other
> platforms.)  I guess XRandR 1.2 covers most of the current uses.

Patch attached. The patch includes your code.
Actually 1.3 is better, it has XRRGetOutputPrimary.  Without it we have to guess.

> 
> Because XRandR or Xinerama doesn't help us get information about the
> workarea (that's the task of window managers), we need some function
> like x_get_net_workarea regardless of the use of XRandR or Xinerama.

Right.

> 
> Even with XRandR or Xinerama code, leaving the GDK code would be
> meaningful because we may have yet another framework for multiple
> monitor support (GDK already covers 3 of them on X11) in future.

Gdk covers the "Xinerama on Solaris" case which is a bit different.  I don't have any Solaris available, so I can't do that.

Another comment:
Your defun is x-display-monitor-attributes-list.  Aren't we supposed to try to avoid the use of x-prefixed functions?  display-monitor-attributes-list sounds fine to me.

	Jan D.



[-- Attachment #2: randr.diff --]
[-- Type: application/octet-stream, Size: 24614 bytes --]

=== modified file 'configure.ac'
--- configure.ac	2013-04-26 19:31:09 +0000
+++ configure.ac	2013-04-28 17:03:38 +0000
@@ -2814,6 +2814,57 @@
 fi
 AC_SUBST(LIBXSM)
 
+### Use XRandr (-lXrandr) if available
+HAVE_XRANDR=no
+if test "${HAVE_X11}" = "yes"; then
+  XRANDR_REQUIRED=1.2.2
+  XRANDR_MODULES="xrandr >= $XRANDR_REQUIRED"
+  PKG_CHECK_MODULES(XRANDR, $XRANDR_MODULES, HAVE_XRANDR=yes, HAVE_XRANDR=no)
+  if test $HAVE_XRANDR = no; then
+    # Test old way in case pkg-config doesn't have it (older machines).
+    AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+      [AC_CHECK_LIB(XRANDR, XRRQueryExtension, HAVE_XRANDR=yes, , -lXrandr)])
+    if test $HAVE_XRANDR = yes; then
+      XRANDR_LIBS=-lXrandr
+      AC_SUBST(XRANDR_LIBS)
+    fi
+  fi
+  if test $HAVE_XRANDR = yes; then
+    SAVE_CFLAGS="$CFLAGS"
+    SAVE_LIBS="$LIBS"
+    CFLAGS="$XRANDR_CFLAGS $CFLAGS"
+    LIBS="$XRANDR_LIBS $LIBS"
+    AC_CHECK_FUNCS(XRRGetOutputPrimary)
+    CFLAGS="$SAVE_CFLAGS"
+    LIBS="$SAVE_LIBS"
+
+    AC_DEFINE(HAVE_XRANDR, 1, [Define to 1 if you have the XRandr extension.])
+  fi
+fi
+
+### Use Xinerama (-lXinerama) if available
+HAVE_XINERAMA=no
+if test "${HAVE_X11}" = "yes"; then
+  XINERAMA_REQUIRED=1.0.2
+  XINERAMA_MODULES="xinerama >= $XINERAMA_REQUIRED"
+  PKG_CHECK_MODULES(XINERAMA, $XINERAMA_MODULES, HAVE_XINERAMA=yes, 
+                    HAVE_XINERAMA=no)
+  if test $HAVE_XINERAMA = no; then
+    # Test old way in case pkg-config doesn't have it (older machines).
+    AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+      [AC_CHECK_LIB(XINERAMA, XineramaQueryExtension,
+                    HAVE_XINERAMA=yes, , -lXinerama)])
+    if test $HAVE_XINERAMA = yes; then
+      XINERAMA_LIBS=-lXinerama
+      AC_SUBST(XINERAMA_LIBS)
+    fi
+  fi
+  if test $HAVE_XINERAMA = yes; then
+    AC_DEFINE(HAVE_XINERAMA, 1, [Define to 1 if you have the Xinerama extension.])
+  fi
+fi
+
+
 ### Use libxml (-lxml2) if available
 HAVE_LIBXML2=no
 if test "${with_xml2}" != "no"; then

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2013-04-22 05:18:30 +0000
+++ src/Makefile.in	2013-04-28 16:31:43 +0000
@@ -232,6 +232,12 @@
 LIBXML2_LIBS = @LIBXML2_LIBS@
 LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
 
+XRANDR_LIBS = @XRANDR_LIBS@
+XRANDR_CFLAGS = @XRANDR_CFLAGS@
+
+XINERAMA_LIBS = @XINERAMA_LIBS@
+XINERAMA_CFLAGS = @XINERAMA_CFLAGS@
+
 ## widget.o if USE_X_TOOLKIT, otherwise empty.
 WIDGET_OBJ=@WIDGET_OBJ@
 
@@ -315,7 +321,7 @@
   -I$(lib) -I$(srcdir)/../lib \
   $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
   $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
-  $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \
+  $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
   $(LIBGNUTLS_CFLAGS) \
@@ -393,7 +399,7 @@
    $(LIBX_OTHER) $(LIBSOUND) \
    $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \
    $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
-   $(LIB_EXECINFO) \
+   $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) \
    $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \

=== modified file 'src/xfns.c'
--- src/xfns.c	2013-04-07 04:41:19 +0000
+++ src/xfns.c	2013-04-28 17:04:07 +0000
@@ -59,6 +59,13 @@
 
 #include "xsettings.h"
 
+#ifdef HAVE_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+#ifdef HAVE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
 #ifdef USE_GTK
 #include "gtkutil.h"
 #endif
@@ -126,6 +133,7 @@
 static Lisp_Object Qsuppress_icon;
 static Lisp_Object Qundefined_color;
 static Lisp_Object Qcompound_text, Qcancel_timer;
+static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes;
 Lisp_Object Qfont_param;
 
 #ifdef GLYPH_DEBUG
@@ -3791,6 +3799,548 @@
   else
     return Qnil;
 }
+
+/* Return an alist of the form
+   ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+    (width . WIDTH) (height . HEIGHT))
+   with converting XOFFSET, YOFFSET, WIDTH and HEIGHT to Lisp
+   integers.  */
+
+static Lisp_Object
+x_create_geometry_alist (EMACS_INT xoffset, EMACS_INT yoffset,
+			 EMACS_INT width, EMACS_INT height)
+{
+  return list4 (Fcons (Qleft, list2 (Qplus, make_number (xoffset))),
+		Fcons (Qtop, list2 (Qplus, make_number (yoffset))),
+		Fcons (Qwidth, make_number (width)),
+		Fcons (Qheight, make_number (height)));
+}
+
+/* Return an alist of the form ((width . WIDTH) (height . HEIGHT)).
+   with converting WIDTH and HEIGHT to Lisp integers.  */
+
+static Lisp_Object
+x_create_size_alist (EMACS_INT width, EMACS_INT height)
+{
+  return list2 (Fcons (Qwidth, make_number (width)),
+		Fcons (Qheight, make_number (height)));
+}
+
+/* Store the geometry of the workarea on display DPYINFO into *RECT.
+   Return false if and only if the workarea information cannot be
+   obtained via the _NET_WORKAREA root window property.  */
+
+static bool
+x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect)
+{
+  Display *dpy = dpyinfo->display;
+  long offset, max_len;
+  Atom target_type, actual_type;
+  unsigned long actual_size, bytes_remaining;
+  int rc, actual_format;
+  unsigned char *tmp_data = NULL;
+  bool result = false;
+
+  x_catch_errors (dpy);
+  offset = 0;
+  max_len = 1;
+  target_type = XA_CARDINAL;
+  rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+			   dpyinfo->Xatom_net_current_desktop,
+			   offset, max_len, False, target_type,
+			   &actual_type, &actual_format, &actual_size,
+			   &bytes_remaining, &tmp_data);
+  if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+      && actual_format == 32 && actual_size == max_len)
+    {
+      long current_desktop = ((long *) tmp_data)[0];
+
+      XFree (tmp_data);
+      tmp_data = NULL;
+
+      offset = 4 * current_desktop;
+      max_len = 4;
+      rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+			       dpyinfo->Xatom_net_workarea,
+			       offset, max_len, False, target_type,
+			       &actual_type, &actual_format, &actual_size,
+			       &bytes_remaining, &tmp_data);
+      if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+	  && actual_format == 32 && actual_size == max_len)
+	{
+	  long *workareas = (long *) tmp_data;
+
+	  rect->x = workareas[0];
+	  rect->y = workareas[1];
+	  rect->width = workareas[2];
+	  rect->height = workareas[3];
+
+	  XFree (tmp_data);
+	  tmp_data = NULL;
+
+	  result = true;
+	}
+    }
+  if (tmp_data)
+    XFree (tmp_data);
+  x_uncatch_errors ();
+
+  return result;
+}
+
+struct MonitorInfo {
+  XRectangle geom, work;
+  int mm_width, mm_height;
+};
+
+/* Return monitor number where F is "most" or closest to.  */
+static int
+x_get_monitor_for_frame (struct frame *f,
+                         struct MonitorInfo *monitors,
+                         int n_monitors)
+{
+  XRectangle frect;
+  int area = 0, dist = -1;
+  int best_area = -1, best_dist = -1;
+  int i;
+
+  if (n_monitors == 1) return 0;
+  frect.x = f->left_pos;
+  frect.y = f->top_pos;
+  frect.width = FRAME_PIXEL_WIDTH (f);
+  frect.height = FRAME_PIXEL_HEIGHT (f);
+
+  for (i = 0; i < n_monitors; ++i)
+    {
+      struct MonitorInfo *mi = &monitors[i];
+      XRectangle res;
+      int a = 0;
+
+      if (mi->geom.width == 0) continue;
+
+      if (x_intersect_rectangles (&mi->geom, &frect, &res))
+        {
+          a = res.width * res.height;
+          if (a > area) {
+            area = a;
+            best_area = i;
+          }
+        }
+
+      if (a == 0 && area == 0)
+        {
+          int dx, dy, d;
+          if (frect.x + frect.width < mi->geom.x)
+            dx = mi->geom.x - frect.x + frect.width;
+          else if (frect.x > mi->geom.x + mi->geom.width)
+            dx = frect.x - mi->geom.x + mi->geom.width;
+          else
+            dx = 0;
+          if (frect.y + frect.height < mi->geom.y)
+            dy = mi->geom.y - frect.y + frect.height;
+          else if (frect.y > mi->geom.y + mi->geom.height)
+            dy = frect.y - mi->geom.y + mi->geom.height;
+          else
+            dy = 0;
+
+          d = dx*dx + dy*dy;
+          if (dist == -1 || dist > d)
+            {
+              dist = d;
+              best_dist = i;
+            }
+        }
+    }
+
+  return best_area != -1 ? best_area : (best_dist != -1 ? best_dist : 0);
+}
+
+static Lisp_Object
+x_make_monitor_attribute_list (struct MonitorInfo *monitors,
+                               int n_monitors,
+                               int primary_monitor,
+                               struct x_display_info *dpyinfo)
+{
+  Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+  Lisp_Object frame, rest, attributes_list = Qnil;
+  Lisp_Object primary_monitor_attributes = Qnil;
+  int i;
+
+  FOR_EACH_FRAME (rest, frame)
+    {
+      struct frame *f = XFRAME (frame);
+
+      if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+	  && !EQ (frame, tip_frame))
+	{
+	  i = x_get_monitor_for_frame (f, monitors, n_monitors);
+	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+	}
+    }
+  
+  for (i = 0; i < n_monitors; ++i) 
+    {
+      Lisp_Object geometry, workarea, attributes = Qnil;
+      struct MonitorInfo *mi = &monitors[i];
+
+      if (mi->geom.width == 0) continue;
+
+      workarea = x_create_geometry_alist (mi->work.x, mi->work.y,
+                                          mi->work.width, mi->work.height);
+      geometry = x_create_geometry_alist (mi->geom.x, mi->geom.y,
+                                          mi->geom.width, mi->geom.height);
+      attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+			  attributes);
+      attributes = Fcons (Fcons (Qmm_size,
+                                 x_create_size_alist (mi->mm_width,
+                                                      mi->mm_height)),
+                          attributes);
+      attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+      attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+
+      if (i == primary_monitor)
+        primary_monitor_attributes = attributes;
+      else
+        attributes_list = Fcons (attributes, attributes_list);
+    }
+
+  if (!NILP (primary_monitor_attributes))
+    attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+
+}
+
+static Lisp_Object
+x_get_monitor_attributes_fallback (struct x_display_info *dpyinfo)
+{
+  struct MonitorInfo monitor;
+  int width_mm, height_mm;
+  XRectangle workarea_r;
+
+  /* Fallback: treat (possibly) multiple physical monitors as if they
+     formed a single monitor as a whole.  This should provide a
+     consistent result at least on single monitor environments.  */
+  monitor.geom.x = monitor.geom.y = 0;
+  monitor.geom.width = x_display_pixel_width (dpyinfo);
+  monitor.geom.height = x_display_pixel_height (dpyinfo);
+  monitor.mm_width = WidthMMOfScreen (dpyinfo->screen);
+  monitor.mm_height = HeightMMOfScreen (dpyinfo->screen);
+  if (x_get_net_workarea (dpyinfo, &workarea_r))
+    monitor.work = workarea_r;
+  else
+    monitor.work = monitor.geom;
+  return x_make_monitor_attribute_list (&monitor, 1, 0, dpyinfo);
+}
+
+
+#ifdef HAVE_XINERAMA
+static Lisp_Object
+x_get_monitor_attributes_xinerama (struct x_display_info *dpyinfo)
+{
+  int n_monitors, i;
+  Lisp_Object attributes_list = Qnil;
+  Display *dpy = dpyinfo->display;
+  XineramaScreenInfo *info = XineramaQueryScreens (dpy, &n_monitors);
+  struct MonitorInfo *monitors;
+  float mm_width_per_pixel, mm_height_per_pixel;
+
+  if (! info) return attributes_list;
+
+  mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
+			/ x_display_pixel_width (dpyinfo));
+  mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
+			 / x_display_pixel_height (dpyinfo));
+  monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors));
+  for (i = 0; i < n_monitors; ++i) 
+    {
+      struct MonitorInfo *mi = &monitors[i];
+      XRectangle workarea_r;
+
+      mi->geom.x = info[i].x_org;
+      mi->geom.y = info[i].y_org;
+      mi->geom.width = info[i].width;
+      mi->geom.height = info[i].height;
+      mi->mm_width = mi->geom.width * mm_width_per_pixel + 0.5;
+      mi->mm_height = mi->geom.height * mm_height_per_pixel + 0.5;
+
+      /* Xinerama usually have primary monitor first, just use that.  */
+      if (i == 0 && x_get_net_workarea (dpyinfo, &workarea_r))
+            {
+              mi->work = workarea_r;
+              if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work))
+                mi->work = mi->geom;
+            }
+          else
+            mi->work = mi->geom;
+    }
+  XFree (info);
+
+  attributes_list = x_make_monitor_attribute_list (monitors,
+                                                   n_monitors,
+                                                   0,
+                                                   dpyinfo);
+  xfree (monitors);
+  return attributes_list;
+  
+}
+#endif /* HAVE_XINERAMA */
+
+
+#ifdef HAVE_XRANDR
+static Lisp_Object
+x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo)
+{
+  Lisp_Object attributes_list = Qnil;
+  XRRScreenResources *resources;
+  Display *dpy = dpyinfo->display;
+  int i, n_monitors, primary = -1;
+  RROutput pxid = None;
+  struct MonitorInfo *monitors;
+
+  resources = XRRGetScreenResourcesCurrent (dpy, dpyinfo->root_window);
+  if (! resources) return Qnil;
+  n_monitors = resources->noutput;
+  monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors));
+
+#ifdef HAVE_XRRGETOUTPUTPRIMARY
+  pxid = XRRGetOutputPrimary (dpy, dpyinfo->root_window);
+#endif
+
+  for (i = 0; i < n_monitors; ++i) 
+    {
+      XRROutputInfo *info = XRRGetOutputInfo (dpy, resources,
+                                              resources->outputs[i]);
+      Connection conn = info ? info->connection : RR_Disconnected;
+      RRCrtc id = info ? info->crtc : None;
+      
+      if (conn != RR_Disconnected && id != None)
+        {
+          XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, id);
+          struct MonitorInfo *mi = &monitors[i];
+          XRectangle workarea_r;
+
+          if (! crtc) continue;
+
+          mi->geom.x = crtc->x;
+          mi->geom.y = crtc->y;
+          mi->geom.width = crtc->width;
+          mi->geom.height = crtc->height;
+          mi->mm_width = info->mm_width;
+          mi->mm_height = info->mm_height;
+
+          if (pxid != None && pxid == resources->outputs[i])
+            primary = i;
+          else if (primary == -1 && strcmp (info->name, "LVDS") == 0)
+            primary = i;
+                
+          if (i == primary && x_get_net_workarea (dpyinfo, &workarea_r))
+            {
+              mi->work= workarea_r;
+              if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work))
+                mi->work = mi->geom;
+            }
+          else
+            mi->work = mi->geom;
+
+          XRRFreeCrtcInfo (crtc);
+        }
+      XRRFreeOutputInfo (info);
+    }
+  XRRFreeScreenResources (resources);
+
+  attributes_list = x_make_monitor_attribute_list (monitors,
+                                                   n_monitors,
+                                                   primary,
+                                                   dpyinfo);
+  xfree (monitors);
+  return attributes_list;
+}
+#endif /* HAVE_XRANDR */
+
+static Lisp_Object
+x_get_monitor_attributes (struct x_display_info *dpyinfo)
+{
+  Lisp_Object attributes_list = Qnil;
+  Display *dpy = dpyinfo->display;
+
+#ifdef HAVE_XRANDR
+  int xrr_event_base, xrr_error_base;
+  bool xrr_ok = false;
+  xrr_ok = XRenderQueryExtension (dpy, &xrr_event_base, &xrr_error_base);
+  if (xrr_ok)
+    {
+      int xrr_major, xrr_minor;
+      XRRQueryVersion (dpy, &xrr_major, &xrr_minor);
+      xrr_ok = (xrr_major == 1 && xrr_minor >= 2) || xrr_major > 1;
+    }
+
+  if (xrr_ok)
+    attributes_list = x_get_monitor_attributes_xrandr (dpyinfo);
+#endif /* HAVE_XRANDR */
+
+#ifdef HAVE_XINERAMA
+  if (NILP (attributes_list))
+    {
+      int xin_event_base, xin_error_base;
+      bool xin_ok = false;
+      xin_ok = XineramaQueryExtension (dpy, &xin_event_base, &xin_error_base);
+      if (xin_ok && XineramaIsActive (dpy))
+        attributes_list = x_get_monitor_attributes_xinerama (dpyinfo);
+    }
+#endif /* HAVE_XINERAMA */
+
+  if (NILP (attributes_list))
+    attributes_list = x_get_monitor_attributes_fallback (dpyinfo);
+
+  return attributes_list;
+}
+
+DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
+       Sx_display_monitor_attributes_list,
+       0, 1, 0,
+       doc: /* Return a list of physical monitor attributes on X display.
+Each element of the list represents the attributes of each physical
+monitor.  The first element corresponds to the primary monitor.
+
+Attributes for a physical monitor is represented as an alist of
+attribute names and values as follows:
+
+    Name     | Value
+    ---------+--------------------------------------------------
+    geometry | Position and size in the form of
+	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+	     |  (width . WIDTH) (height . HEIGHT)).
+	     |
+    workarea | Position and size of the workarea in the form of
+	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+	     |  (width . WIDTH) (height . HEIGHT)).
+	     |
+    mm-size  | Width and height in millimeters in the form of
+	     | ((width . WIDTH) (height . HEIGHT)).
+	     |
+    frames   | List of frames belonging to the physical monitor.
+
+where XOFFSET, YOFFSET, WIDTH, and HEIGHT are integers.  A frame
+belongs to a monitor when either the largest area of the frame resides
+in the monitor, or the monitor is the closest to the frame if the
+frame does not intersect any monitors.  Every non-tip frame (including
+invisible one) in a graphical display belongs to exactly one monitor.
+
+The optional argument TERMINAL specifies which display to ask about.
+TERMINAL should be a terminal object, a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display.  */)
+  (Lisp_Object terminal)
+{
+  struct x_display_info *dpyinfo = check_x_display_info (terminal);
+  Lisp_Object attributes_list = Qnil;
+
+#ifdef USE_GTK
+  float mm_width_per_pixel, mm_height_per_pixel;
+  GdkDisplay *gdpy;
+  GdkScreen *gscreen;
+  gint primary_monitor = 0, n_monitors, i;
+  Lisp_Object primary_monitor_attributes = Qnil;
+  Lisp_Object monitor_frames, rest, frame;
+
+  block_input ();
+  mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
+			/ x_display_pixel_width (dpyinfo));
+  mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
+			 / x_display_pixel_height (dpyinfo));
+  gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+  gscreen = gdk_display_get_default_screen (gdpy);
+#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 20
+  primary_monitor = gdk_screen_get_primary_monitor (gscreen);
+#endif
+  n_monitors = gdk_screen_get_n_monitors (gscreen);
+  monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+  FOR_EACH_FRAME (rest, frame)
+    {
+      struct frame *f = XFRAME (frame);
+
+      if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+	  && !EQ (frame, tip_frame))
+	{
+	  GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+
+	  i = gdk_screen_get_monitor_at_window (gscreen, gwin);
+	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+	}
+    }
+
+  i = n_monitors;
+  while (i-- > 0)
+    {
+      Lisp_Object geometry, workarea, attributes = Qnil;
+      gint width_mm = -1, height_mm = -1;
+      GdkRectangle rec;
+
+      attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+			  attributes);
+
+      gdk_screen_get_monitor_geometry (gscreen, i, &rec);
+      geometry = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
+
+#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 14
+      width_mm = gdk_screen_get_monitor_width_mm (gscreen, i);
+      height_mm = gdk_screen_get_monitor_height_mm (gscreen, i);
+#endif
+      if (width_mm < 0)
+	width_mm = rec.width * mm_width_per_pixel + 0.5;
+      if (height_mm < 0)
+	height_mm = rec.height * mm_height_per_pixel + 0.5;
+      attributes = Fcons (Fcons (Qmm_size,
+				 x_create_size_alist (width_mm, height_mm)),
+			  attributes);
+
+#if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4)
+      gdk_screen_get_monitor_workarea (gscreen, i, &rec);
+      workarea = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
+#else
+      /* Emulate the behavior of GTK+ 3.4.  */
+      {
+	XRectangle workarea_r;
+
+	workarea = Qnil;
+	if (i == primary_monitor && x_get_net_workarea (dpyinfo, &workarea_r))
+	  {
+	    GdkRectangle work;
+
+	    work.x = workarea_r.x;
+	    work.y = workarea_r.y;
+	    work.width = workarea_r.width;
+	    work.height = workarea_r.height;
+	    if (gdk_rectangle_intersect (&rec, &work, &work))
+	      workarea = x_create_geometry_alist (work.x, work.y,
+						  work.width, work.height);
+	  }
+	if (NILP (workarea))
+	  workarea = geometry;
+      }
+#endif
+      attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+
+      attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+
+      if (i == primary_monitor)
+	primary_monitor_attributes = attributes;
+      else
+	attributes_list = Fcons (attributes, attributes_list);
+    }
+
+  if (!NILP (primary_monitor_attributes))
+    attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+  unblock_input ();
+#else  /* not USE_GTK */
+
+  block_input ();
+  attributes_list = x_get_monitor_attributes (dpyinfo);
+  unblock_input ();
+
+#endif	/* not USE_GTK */
+
+  return attributes_list;
+}
+
 \f
 int
 x_pixel_width (register struct frame *f)
@@ -5701,6 +6251,10 @@
   DEFSYM (Qundefined_color, "undefined-color");
   DEFSYM (Qcompound_text, "compound-text");
   DEFSYM (Qcancel_timer, "cancel-timer");
+  DEFSYM (Qgeometry, "geometry");
+  DEFSYM (Qworkarea, "workarea");
+  DEFSYM (Qmm_size, "mm-size");
+  DEFSYM (Qframes, "frames");
   DEFSYM (Qfont_param, "font-parameter");
   /* This is the end of symbol initialization.  */
 
@@ -5864,6 +6418,7 @@
   defsubr (&Sx_display_visual_class);
   defsubr (&Sx_display_backing_store);
   defsubr (&Sx_display_save_under);
+  defsubr (&Sx_display_monitor_attributes_list);
   defsubr (&Sx_wm_set_size_hint);
   defsubr (&Sx_create_frame);
   defsubr (&Sx_open_connection);

=== modified file 'src/xterm.c'
--- src/xterm.c	2013-03-25 17:58:35 +0000
+++ src/xterm.c	2013-04-28 12:00:47 +0000
@@ -10251,6 +10251,8 @@
       { "_NET_WM_WINDOW_OPACITY", &dpyinfo->Xatom_net_wm_window_opacity },
       { "_NET_ACTIVE_WINDOW", &dpyinfo->Xatom_net_active_window },
       { "_NET_FRAME_EXTENTS", &dpyinfo->Xatom_net_frame_extents },
+      { "_NET_CURRENT_DESKTOP", &dpyinfo->Xatom_net_current_desktop },
+      { "_NET_WORKAREA", &dpyinfo->Xatom_net_workarea },
       /* Session management */
       { "SM_CLIENT_ID", &dpyinfo->Xatom_SM_CLIENT_ID },
       { "_XSETTINGS_SETTINGS", &dpyinfo->Xatom_xsettings_prop },

=== modified file 'src/xterm.h'
--- src/xterm.h	2013-04-07 04:41:19 +0000
+++ src/xterm.h	2013-04-28 12:00:47 +0000
@@ -346,7 +346,8 @@
   Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
     Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
     Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
-    Xatom_net_frame_extents;
+    Xatom_net_frame_extents,
+    Xatom_net_current_desktop, Xatom_net_workarea;
 
   /* XSettings atoms and windows.  */
   Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;


[-- Attachment #3: Type: text/plain, Size: 4 bytes --]






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

* Re: x-display-pixel-width/height inconsistency
  2013-04-28 17:16                           ` Jan D.
@ 2013-04-29  2:27                             ` YAMAMOTO Mitsuharu
  2013-04-29  2:42                               ` YAMAMOTO Mitsuharu
  2013-05-01  9:58                               ` Jan Djärv
  0 siblings, 2 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-04-29  2:27 UTC (permalink / raw)
  To: Jan D.; +Cc: emacs-devel

>>>>> On Sun, 28 Apr 2013 19:16:25 +0200, "Jan D." <jan.h.d@swipnet.se> said:

>>> A general objection is that XRandr/Xinerama is not used, so the
>>> non-Gtk+ code relies on a freedesktop compliant window manager,
>>> rather than taking the general approach.  If XRandr/Xinerama is
>>> used, no split between Gtk+ and non-Gtk+ code is needed.
>>> Xrandr/Xinerama is what Gtk+ use anyway so we are not adding any
>>> new dependencies.
>> 
>> Of course, patches welcome.  (And also for implementations for
>> other platforms.)  I guess XRandR 1.2 covers most of the current
>> uses.

> Patch attached. The patch includes your code.  Actually 1.3 is
> better, it has XRRGetOutputPrimary.  Without it we have to guess.

Thanks.  It was so quick!

I found a couple of trivial mistakes in the patch:

  * In x_get_monitor_attributes:
    `XRenderQueryExtension' should be `XRRQueryExtension'.

  * In x_make_monitor_attribute_list:
    `return attributes_list' is missing at the end.

Even with the above fixes, I got different results between GDK and
XRandR implementations with Xquartz 2.7.4 on OS X 10.8.

  GDK:

  (((geometry (left + 0) (top + 22) (width . 2560) (height . 1418))
    (workarea (left + 0) (top + 22) (width . 2560) (height . 1418))
    (mm-size (width . 677) (height . 374))
    (frames #<frame emacs@YAMAMOTO-no-iMac.local 0x1042b4050>))
   ((geometry (left + 2560) (top + 0) (width . 960) (height . 600))
    (workarea (left + 2560) (top + 0) (width . 960) (height . 600))
    (mm-size (width . 254) (height . 158))
    (frames)))

  XRandR:

  (((geometry (left + 0) (top + 0) (width . 3520) (height . 1440))
    (workarea (left + 0) (top + 0) (width . 3520) (height . 1440))
    (mm-size (width . 0) (height . 0))
    (frames #<frame emacs@YAMAMOTO-no-iMac.local 0x1022ae850>)))

  (Xinerama gave the same result as GDK did.)

As you can see, there is a difference even in the number of monitors.

Maybe you need to register some callback to call
XRRUpdateConfiguration?  XRANDR manual says:

  Xlib notification

  Clients must call back into Xlib using XRRUpdateConfiguration when
  screen configuration change notify events are generated (or root
  window configuration changes occur, to update Xlib’s view of the
  resolution, size, rotation, reflection or subpixel order. Generally,
  toolkits will perform this operation on behalf of applications; we
  did not want to change display structure data behind the back of
  toolkits, as in multithreaded clients, various race conditions might
  occur. Toolkits should provide clients some mechanism for
  notification of screen change, of course.

  (http://www.x.org/archive/current/doc/man/man3/Xrandr.3.xhtml)

> Another comment: Your defun is x-display-monitor-attributes-list.
> Aren't we supposed to try to avoid the use of x-prefixed functions?
> display-monitor-attributes-list sounds fine to me.

Actually I'm not so familiar with this naming convention matter, and
just followed the other old x-display-* functions.  Feel free to
adjust it for (new?) convention.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-04-29  2:27                             ` YAMAMOTO Mitsuharu
@ 2013-04-29  2:42                               ` YAMAMOTO Mitsuharu
  2013-05-01  9:58                               ` Jan Djärv
  1 sibling, 0 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-04-29  2:42 UTC (permalink / raw)
  To: Jan D.; +Cc: emacs-devel

>>>>> On Mon, 29 Apr 2013 11:27:47 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

> Even with the above fixes, I got different results between GDK and
> XRandR implementations with Xquartz 2.7.4 on OS X 10.8.

>   GDK:

>   (((geometry (left + 0) (top + 22) (width . 2560) (height . 1418))
>     (workarea (left + 0) (top + 22) (width . 2560) (height . 1418))
>     (mm-size (width . 677) (height . 374))
>     (frames #<frame emacs@YAMAMOTO-no-iMac.local 0x1042b4050>))
>    ((geometry (left + 2560) (top + 0) (width . 960) (height . 600))
>     (workarea (left + 2560) (top + 0) (width . 960) (height . 600))
>     (mm-size (width . 254) (height . 158))
>     (frames)))

>   XRandR:

>   (((geometry (left + 0) (top + 0) (width . 3520) (height . 1440))
>     (workarea (left + 0) (top + 0) (width . 3520) (height . 1440))
>     (mm-size (width . 0) (height . 0))
>     (frames #<frame emacs@YAMAMOTO-no-iMac.local 0x1022ae850>)))

>   (Xinerama gave the same result as GDK did.)

> As you can see, there is a difference even in the number of monitors.

> Maybe you need to register some callback to call
> XRRUpdateConfiguration?

This guess was not right.  GDK rejects XRandR in Xquartz and uses
Xinerama instead.  The distinction is made by comparing the output
name with "default".

in init_randr13 (gdkscreen-x11.c):

      XRROutputInfo *output =
	XRRGetOutputInfo (dpy, resources, resources->outputs[i]);

      /* Non RandR1.2 X driver have output name "default" */
      randr12_compat |= !g_strcmp0 (output->name, "default");

	:

  /* non RandR 1.2 X driver doesn't return any usable multihead data */
  if (randr12_compat)
    {
      guint n_monitors = monitors->len;

      free_monitors ((GdkX11Monitor *)g_array_free (monitors, FALSE),
		     n_monitors);

      return FALSE;
    }

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-04-29  2:27                             ` YAMAMOTO Mitsuharu
  2013-04-29  2:42                               ` YAMAMOTO Mitsuharu
@ 2013-05-01  9:58                               ` Jan Djärv
  2013-05-02  4:09                                 ` YAMAMOTO Mitsuharu
  1 sibling, 1 reply; 97+ messages in thread
From: Jan Djärv @ 2013-05-01  9:58 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1209 bytes --]

Hello.

29 apr 2013 kl. 04:27 skrev YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>:

> I found a couple of trivial mistakes in the patch:
> 
>  * In x_get_monitor_attributes:
>    `XRenderQueryExtension' should be `XRRQueryExtension'.
> 
>  * In x_make_monitor_attribute_list:
>    `return attributes_list' is missing at the end.
> 

Good, I've fixed those in the new patch (attached).

> This guess was not right.  GDK rejects XRandR in Xquartz and uses
> Xinerama instead.  The distinction is made by comparing the output
> name with "default".
> 
> in init_randr13 (gdkscreen-x11.c):
> 
>      XRROutputInfo *output =
> 	XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
> 
>      /* Non RandR1.2 X driver have output name "default" */
>      randr12_compat |= !g_strcmp0 (output->name, "default");

I did not know that.  I've made adjustments for this in the patch, tested on XQuartz which indeed does not seem to have a 1.2-compatible driver.  Strange that.

I also added name and source (the latter mostly for debugging) to the Lisp structure returned.
I also check for XRRGetScreenResourcesCurrent in configure as that is a 1.3 version function.

	Jan D.


[-- Attachment #2: randr.diff --]
[-- Type: application/octet-stream, Size: 26510 bytes --]

=== modified file 'configure.ac'
--- configure.ac	2013-04-26 19:31:09 +0000
+++ configure.ac	2013-05-01 09:53:07 +0000
@@ -2814,6 +2814,57 @@
 fi
 AC_SUBST(LIBXSM)
 
+### Use XRandr (-lXrandr) if available
+HAVE_XRANDR=no
+if test "${HAVE_X11}" = "yes"; then
+  XRANDR_REQUIRED=1.2.2
+  XRANDR_MODULES="xrandr >= $XRANDR_REQUIRED"
+  PKG_CHECK_MODULES(XRANDR, $XRANDR_MODULES, HAVE_XRANDR=yes, HAVE_XRANDR=no)
+  if test $HAVE_XRANDR = no; then
+    # Test old way in case pkg-config doesn't have it (older machines).
+    AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+      [AC_CHECK_LIB(XRANDR, XRRQueryExtension, HAVE_XRANDR=yes, , -lXrandr)])
+    if test $HAVE_XRANDR = yes; then
+      XRANDR_LIBS=-lXrandr
+      AC_SUBST(XRANDR_LIBS)
+    fi
+  fi
+  if test $HAVE_XRANDR = yes; then
+    SAVE_CFLAGS="$CFLAGS"
+    SAVE_LIBS="$LIBS"
+    CFLAGS="$XRANDR_CFLAGS $CFLAGS"
+    LIBS="$XRANDR_LIBS $LIBS"
+    AC_CHECK_FUNCS(XRRGetOutputPrimary XRRGetScreenResourcesCurrent)
+    CFLAGS="$SAVE_CFLAGS"
+    LIBS="$SAVE_LIBS"
+
+    AC_DEFINE(HAVE_XRANDR, 1, [Define to 1 if you have the XRandr extension.])
+  fi
+fi
+
+### Use Xinerama (-lXinerama) if available
+HAVE_XINERAMA=no
+if test "${HAVE_X11}" = "yes"; then
+  XINERAMA_REQUIRED=1.0.2
+  XINERAMA_MODULES="xinerama >= $XINERAMA_REQUIRED"
+  PKG_CHECK_MODULES(XINERAMA, $XINERAMA_MODULES, HAVE_XINERAMA=yes, 
+                    HAVE_XINERAMA=no)
+  if test $HAVE_XINERAMA = no; then
+    # Test old way in case pkg-config doesn't have it (older machines).
+    AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+      [AC_CHECK_LIB(XINERAMA, XineramaQueryExtension,
+                    HAVE_XINERAMA=yes, , -lXinerama)])
+    if test $HAVE_XINERAMA = yes; then
+      XINERAMA_LIBS=-lXinerama
+      AC_SUBST(XINERAMA_LIBS)
+    fi
+  fi
+  if test $HAVE_XINERAMA = yes; then
+    AC_DEFINE(HAVE_XINERAMA, 1, [Define to 1 if you have the Xinerama extension.])
+  fi
+fi
+
+
 ### Use libxml (-lxml2) if available
 HAVE_LIBXML2=no
 if test "${with_xml2}" != "no"; then

=== modified file 'src/Makefile.in'
--- src/Makefile.in	2013-04-22 05:18:30 +0000
+++ src/Makefile.in	2013-04-28 17:17:40 +0000
@@ -232,6 +232,12 @@
 LIBXML2_LIBS = @LIBXML2_LIBS@
 LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
 
+XRANDR_LIBS = @XRANDR_LIBS@
+XRANDR_CFLAGS = @XRANDR_CFLAGS@
+
+XINERAMA_LIBS = @XINERAMA_LIBS@
+XINERAMA_CFLAGS = @XINERAMA_CFLAGS@
+
 ## widget.o if USE_X_TOOLKIT, otherwise empty.
 WIDGET_OBJ=@WIDGET_OBJ@
 
@@ -315,7 +321,7 @@
   -I$(lib) -I$(srcdir)/../lib \
   $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
   $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
-  $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \
+  $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) \
   $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
   $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
   $(LIBGNUTLS_CFLAGS) \
@@ -393,7 +399,7 @@
    $(LIBX_OTHER) $(LIBSOUND) \
    $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \
    $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
-   $(LIB_EXECINFO) \
+   $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) \
    $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \

=== modified file 'src/xfns.c'
--- src/xfns.c	2013-04-07 04:41:19 +0000
+++ src/xfns.c	2013-05-01 09:53:07 +0000
@@ -59,6 +59,13 @@
 
 #include "xsettings.h"
 
+#ifdef HAVE_XRANDR
+#include <X11/extensions/Xrandr.h>
+#endif
+#ifdef HAVE_XINERAMA
+#include <X11/extensions/Xinerama.h>
+#endif
+
 #ifdef USE_GTK
 #include "gtkutil.h"
 #endif
@@ -126,6 +133,7 @@
 static Lisp_Object Qsuppress_icon;
 static Lisp_Object Qundefined_color;
 static Lisp_Object Qcompound_text, Qcancel_timer;
+static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource;
 Lisp_Object Qfont_param;
 
 #ifdef GLYPH_DEBUG
@@ -3791,6 +3799,596 @@
   else
     return Qnil;
 }
+
+/* Return an alist of the form
+   ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+    (width . WIDTH) (height . HEIGHT))
+   with converting XOFFSET, YOFFSET, WIDTH and HEIGHT to Lisp
+   integers.  */
+
+static Lisp_Object
+x_create_geometry_alist (EMACS_INT xoffset, EMACS_INT yoffset,
+			 EMACS_INT width, EMACS_INT height)
+{
+  return list4 (Fcons (Qleft, list2 (Qplus, make_number (xoffset))),
+		Fcons (Qtop, list2 (Qplus, make_number (yoffset))),
+		Fcons (Qwidth, make_number (width)),
+		Fcons (Qheight, make_number (height)));
+}
+
+/* Return an alist of the form ((width . WIDTH) (height . HEIGHT)).
+   with converting WIDTH and HEIGHT to Lisp integers.  */
+
+static Lisp_Object
+x_create_size_alist (EMACS_INT width, EMACS_INT height)
+{
+  return list2 (Fcons (Qwidth, make_number (width)),
+		Fcons (Qheight, make_number (height)));
+}
+
+/* Store the geometry of the workarea on display DPYINFO into *RECT.
+   Return false if and only if the workarea information cannot be
+   obtained via the _NET_WORKAREA root window property.  */
+
+static bool
+x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect)
+{
+  Display *dpy = dpyinfo->display;
+  long offset, max_len;
+  Atom target_type, actual_type;
+  unsigned long actual_size, bytes_remaining;
+  int rc, actual_format;
+  unsigned char *tmp_data = NULL;
+  bool result = false;
+
+  x_catch_errors (dpy);
+  offset = 0;
+  max_len = 1;
+  target_type = XA_CARDINAL;
+  rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+			   dpyinfo->Xatom_net_current_desktop,
+			   offset, max_len, False, target_type,
+			   &actual_type, &actual_format, &actual_size,
+			   &bytes_remaining, &tmp_data);
+  if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+      && actual_format == 32 && actual_size == max_len)
+    {
+      long current_desktop = ((long *) tmp_data)[0];
+
+      XFree (tmp_data);
+      tmp_data = NULL;
+
+      offset = 4 * current_desktop;
+      max_len = 4;
+      rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+			       dpyinfo->Xatom_net_workarea,
+			       offset, max_len, False, target_type,
+			       &actual_type, &actual_format, &actual_size,
+			       &bytes_remaining, &tmp_data);
+      if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+	  && actual_format == 32 && actual_size == max_len)
+	{
+	  long *workareas = (long *) tmp_data;
+
+	  rect->x = workareas[0];
+	  rect->y = workareas[1];
+	  rect->width = workareas[2];
+	  rect->height = workareas[3];
+
+	  XFree (tmp_data);
+	  tmp_data = NULL;
+
+	  result = true;
+	}
+    }
+  if (tmp_data)
+    XFree (tmp_data);
+  x_uncatch_errors ();
+
+  return result;
+}
+
+struct MonitorInfo {
+  XRectangle geom, work;
+  int mm_width, mm_height;
+  char *name;
+};
+
+static void
+free_monitors (struct MonitorInfo *monitors, int n_monitors)
+{
+  int i;
+  for (i = 0; i < n_monitors; ++i)
+    xfree (monitors[i].name);
+  xfree (monitors);
+}
+
+
+/* Return monitor number where F is "most" or closest to.  */
+static int
+x_get_monitor_for_frame (struct frame *f,
+                         struct MonitorInfo *monitors,
+                         int n_monitors)
+{
+  XRectangle frect;
+  int area = 0, dist = -1;
+  int best_area = -1, best_dist = -1;
+  int i;
+
+  if (n_monitors == 1) return 0;
+  frect.x = f->left_pos;
+  frect.y = f->top_pos;
+  frect.width = FRAME_PIXEL_WIDTH (f);
+  frect.height = FRAME_PIXEL_HEIGHT (f);
+
+  for (i = 0; i < n_monitors; ++i)
+    {
+      struct MonitorInfo *mi = &monitors[i];
+      XRectangle res;
+      int a = 0;
+
+      if (mi->geom.width == 0) continue;
+
+      if (x_intersect_rectangles (&mi->geom, &frect, &res))
+        {
+          a = res.width * res.height;
+          if (a > area) {
+            area = a;
+            best_area = i;
+          }
+        }
+
+      if (a == 0 && area == 0)
+        {
+          int dx, dy, d;
+          if (frect.x + frect.width < mi->geom.x)
+            dx = mi->geom.x - frect.x + frect.width;
+          else if (frect.x > mi->geom.x + mi->geom.width)
+            dx = frect.x - mi->geom.x + mi->geom.width;
+          else
+            dx = 0;
+          if (frect.y + frect.height < mi->geom.y)
+            dy = mi->geom.y - frect.y + frect.height;
+          else if (frect.y > mi->geom.y + mi->geom.height)
+            dy = frect.y - mi->geom.y + mi->geom.height;
+          else
+            dy = 0;
+
+          d = dx*dx + dy*dy;
+          if (dist == -1 || dist > d)
+            {
+              dist = d;
+              best_dist = i;
+            }
+        }
+    }
+
+  return best_area != -1 ? best_area : (best_dist != -1 ? best_dist : 0);
+}
+
+static Lisp_Object
+x_make_monitor_attribute_list (struct MonitorInfo *monitors,
+                               int n_monitors,
+                               int primary_monitor,
+                               struct x_display_info *dpyinfo,
+                               const char *source)
+{
+  Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+  Lisp_Object frame, rest, attributes_list = Qnil;
+  Lisp_Object primary_monitor_attributes = Qnil;
+  int i;
+
+  FOR_EACH_FRAME (rest, frame)
+    {
+      struct frame *f = XFRAME (frame);
+
+      if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+	  && !EQ (frame, tip_frame))
+	{
+	  i = x_get_monitor_for_frame (f, monitors, n_monitors);
+	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+	}
+    }
+  
+  for (i = 0; i < n_monitors; ++i) 
+    {
+      Lisp_Object geometry, workarea, attributes = Qnil;
+      struct MonitorInfo *mi = &monitors[i];
+
+      if (mi->geom.width == 0) continue;
+
+      workarea = x_create_geometry_alist (mi->work.x, mi->work.y,
+                                          mi->work.width, mi->work.height);
+      geometry = x_create_geometry_alist (mi->geom.x, mi->geom.y,
+                                          mi->geom.width, mi->geom.height);
+      attributes = Fcons (Fcons (Qsource,
+                                 make_string (source, strlen (source))),
+                          attributes);
+      attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+			  attributes);
+      attributes = Fcons (Fcons (Qmm_size,
+                                 x_create_size_alist (mi->mm_width,
+                                                      mi->mm_height)),
+                          attributes);
+      attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+      attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+      if (mi->name)
+        attributes = Fcons (Fcons (Qname, make_string (mi->name,
+                                                       strlen (mi->name))),
+                            attributes);
+
+      if (i == primary_monitor)
+        primary_monitor_attributes = attributes;
+      else
+        attributes_list = Fcons (attributes, attributes_list);
+    }
+
+  if (!NILP (primary_monitor_attributes))
+    attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+  return attributes_list;
+}
+
+static Lisp_Object
+x_get_monitor_attributes_fallback (struct x_display_info *dpyinfo)
+{
+  struct MonitorInfo monitor;
+  int width_mm, height_mm;
+  XRectangle workarea_r;
+
+  /* Fallback: treat (possibly) multiple physical monitors as if they
+     formed a single monitor as a whole.  This should provide a
+     consistent result at least on single monitor environments.  */
+  monitor.geom.x = monitor.geom.y = 0;
+  monitor.geom.width = x_display_pixel_width (dpyinfo);
+  monitor.geom.height = x_display_pixel_height (dpyinfo);
+  monitor.mm_width = WidthMMOfScreen (dpyinfo->screen);
+  monitor.mm_height = HeightMMOfScreen (dpyinfo->screen);
+  monitor.name = xstrdup ("combined screen");
+
+  if (x_get_net_workarea (dpyinfo, &workarea_r))
+    monitor.work = workarea_r;
+  else
+    monitor.work = monitor.geom;
+  return x_make_monitor_attribute_list (&monitor, 1, 0, dpyinfo, "fallback");
+}
+
+
+#ifdef HAVE_XINERAMA
+static Lisp_Object
+x_get_monitor_attributes_xinerama (struct x_display_info *dpyinfo)
+{
+  int n_monitors, i;
+  Lisp_Object attributes_list = Qnil;
+  Display *dpy = dpyinfo->display;
+  XineramaScreenInfo *info = XineramaQueryScreens (dpy, &n_monitors);
+  struct MonitorInfo *monitors;
+  float mm_width_per_pixel, mm_height_per_pixel;
+
+  if (! info) return attributes_list;
+
+  mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
+			/ x_display_pixel_width (dpyinfo));
+  mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
+			 / x_display_pixel_height (dpyinfo));
+  monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors));
+  for (i = 0; i < n_monitors; ++i) 
+    {
+      struct MonitorInfo *mi = &monitors[i];
+      XRectangle workarea_r;
+
+      mi->geom.x = info[i].x_org;
+      mi->geom.y = info[i].y_org;
+      mi->geom.width = info[i].width;
+      mi->geom.height = info[i].height;
+      mi->mm_width = mi->geom.width * mm_width_per_pixel + 0.5;
+      mi->mm_height = mi->geom.height * mm_height_per_pixel + 0.5;
+      mi->name = 0;
+
+      /* Xinerama usually have primary monitor first, just use that.  */
+      if (i == 0 && x_get_net_workarea (dpyinfo, &workarea_r))
+            {
+              mi->work = workarea_r;
+              if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work))
+                mi->work = mi->geom;
+            }
+          else
+            mi->work = mi->geom;
+    }
+  XFree (info);
+
+  attributes_list = x_make_monitor_attribute_list (monitors,
+                                                   n_monitors,
+                                                   0,
+                                                   dpyinfo,
+                                                   "Xinerama");
+  free_monitors (monitors, n_monitors);
+  return attributes_list;
+  
+}
+#endif /* HAVE_XINERAMA */
+
+
+#ifdef HAVE_XRANDR
+static Lisp_Object
+x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo)
+{
+  Lisp_Object attributes_list = Qnil;
+  XRRScreenResources *resources;
+  Display *dpy = dpyinfo->display;
+  int i, n_monitors, primary = -1;
+  RROutput pxid = None;
+  struct MonitorInfo *monitors;
+
+#ifdef HAVE_XRRGETSCREENRESOURCESCURRENT
+  resources = XRRGetScreenResourcesCurrent (dpy, dpyinfo->root_window);
+#else
+  resources = XRRGetScreenResources (dpy, dpyinfo->root_window);
+#endif
+  if (! resources) return Qnil;
+  n_monitors = resources->noutput;
+  monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors));
+
+#ifdef HAVE_XRRGETOUTPUTPRIMARY
+  pxid = XRRGetOutputPrimary (dpy, dpyinfo->root_window);
+#endif
+
+  for (i = 0; i < n_monitors; ++i) 
+    {
+      XRROutputInfo *info = XRRGetOutputInfo (dpy, resources,
+                                              resources->outputs[i]);
+      Connection conn = info ? info->connection : RR_Disconnected;
+      RRCrtc id = info ? info->crtc : None;
+      
+      if (strcmp (info->name, "default") == 0)
+        {
+          /* Non XRandr 1.2 driver, does not give useful data.  */
+          free_monitors (monitors, n_monitors);
+          return Qnil;
+        }
+
+      if (conn != RR_Disconnected && id != None)
+        {
+          XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, id);
+          struct MonitorInfo *mi = &monitors[i];
+          XRectangle workarea_r;
+
+          if (! crtc) continue;
+
+          mi->geom.x = crtc->x;
+          mi->geom.y = crtc->y;
+          mi->geom.width = crtc->width;
+          mi->geom.height = crtc->height;
+          mi->mm_width = info->mm_width;
+          mi->mm_height = info->mm_height;
+          mi->name = xstrdup (info->name);
+
+          if (pxid != None && pxid == resources->outputs[i])
+            primary = i;
+          else if (primary == -1 && strcmp (info->name, "LVDS") == 0)
+            primary = i;
+                
+          if (i == primary && x_get_net_workarea (dpyinfo, &workarea_r))
+            {
+              mi->work= workarea_r;
+              if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work))
+                mi->work = mi->geom;
+            }
+          else
+            mi->work = mi->geom;
+
+          XRRFreeCrtcInfo (crtc);
+        }
+      XRRFreeOutputInfo (info);
+    }
+  XRRFreeScreenResources (resources);
+
+  attributes_list = x_make_monitor_attribute_list (monitors,
+                                                   n_monitors,
+                                                   primary,
+                                                   dpyinfo,
+                                                   "XRandr");
+  free_monitors (monitors, n_monitors);
+  return attributes_list;
+}
+#endif /* HAVE_XRANDR */
+
+static Lisp_Object
+x_get_monitor_attributes (struct x_display_info *dpyinfo)
+{
+  Lisp_Object attributes_list = Qnil;
+  Display *dpy = dpyinfo->display;
+
+#ifdef HAVE_XRANDR
+  int xrr_event_base, xrr_error_base;
+  bool xrr_ok = false;
+  xrr_ok = XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base);
+  if (xrr_ok)
+    {
+      int xrr_major, xrr_minor;
+      XRRQueryVersion (dpy, &xrr_major, &xrr_minor);
+      xrr_ok = (xrr_major == 1 && xrr_minor >= 2) || xrr_major > 1;
+    }
+
+  if (xrr_ok)
+    attributes_list = x_get_monitor_attributes_xrandr (dpyinfo);
+#endif /* HAVE_XRANDR */
+
+#ifdef HAVE_XINERAMA
+  if (NILP (attributes_list))
+    {
+      int xin_event_base, xin_error_base;
+      bool xin_ok = false;
+      xin_ok = XineramaQueryExtension (dpy, &xin_event_base, &xin_error_base);
+      if (xin_ok && XineramaIsActive (dpy))
+        attributes_list = x_get_monitor_attributes_xinerama (dpyinfo);
+    }
+#endif /* HAVE_XINERAMA */
+
+  if (NILP (attributes_list))
+    attributes_list = x_get_monitor_attributes_fallback (dpyinfo);
+
+  return attributes_list;
+}
+
+DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
+       Sx_display_monitor_attributes_list,
+       0, 1, 0,
+       doc: /* Return a list of physical monitor attributes on X display.
+Each element of the list represents the attributes of each physical
+monitor.  The first element corresponds to the primary monitor.
+
+Attributes for a physical monitor is represented as an alist of
+attribute names and values as follows:
+
+    Name     | Value
+    ---------+--------------------------------------------------
+    geometry | Position and size in the form of
+	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+	     |  (width . WIDTH) (height . HEIGHT)).
+	     |
+    workarea | Position and size of the workarea in the form of
+	     | ((left . (+ XOFFSET)) (top . (+ YOFFSET))
+	     |  (width . WIDTH) (height . HEIGHT)).
+	     |
+    mm-size  | Width and height in millimeters in the form of
+	     | ((width . WIDTH) (height . HEIGHT)).
+	     |
+    frames   | List of frames belonging to the physical monitor.
+
+where XOFFSET, YOFFSET, WIDTH, and HEIGHT are integers.  A frame
+belongs to a monitor when either the largest area of the frame resides
+in the monitor, or the monitor is the closest to the frame if the
+frame does not intersect any monitors.  Every non-tip frame (including
+invisible one) in a graphical display belongs to exactly one monitor.
+
+The optional argument TERMINAL specifies which display to ask about.
+TERMINAL should be a terminal object, a frame or a display name (a string).
+If omitted or nil, that stands for the selected frame's display.  */)
+  (Lisp_Object terminal)
+{
+  struct x_display_info *dpyinfo = check_x_display_info (terminal);
+  Lisp_Object attributes_list = Qnil;
+
+#ifdef USE_GTK
+  float mm_width_per_pixel, mm_height_per_pixel;
+  GdkDisplay *gdpy;
+  GdkScreen *gscreen;
+  gint primary_monitor = 0, n_monitors, i;
+  Lisp_Object primary_monitor_attributes = Qnil;
+  Lisp_Object monitor_frames, rest, frame;
+  static const char *source = "Gdk";
+
+  block_input ();
+  mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
+			/ x_display_pixel_width (dpyinfo));
+  mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
+			 / x_display_pixel_height (dpyinfo));
+  gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+  gscreen = gdk_display_get_default_screen (gdpy);
+#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 20
+  primary_monitor = gdk_screen_get_primary_monitor (gscreen);
+#endif
+  n_monitors = gdk_screen_get_n_monitors (gscreen);
+  monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+  FOR_EACH_FRAME (rest, frame)
+    {
+      struct frame *f = XFRAME (frame);
+
+      if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+	  && !EQ (frame, tip_frame))
+	{
+	  GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+
+	  i = gdk_screen_get_monitor_at_window (gscreen, gwin);
+	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+	}
+    }
+
+  i = n_monitors;
+  while (i-- > 0)
+    {
+      Lisp_Object geometry, workarea, attributes = Qnil;
+      gint width_mm = -1, height_mm = -1;
+      GdkRectangle rec;
+
+      attributes = Fcons (Fcons (Qsource,
+                                 make_string (source, strlen (source))),
+                          attributes);
+      attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+			  attributes);
+
+      gdk_screen_get_monitor_geometry (gscreen, i, &rec);
+      geometry = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
+
+#if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 14
+      width_mm = gdk_screen_get_monitor_width_mm (gscreen, i);
+      height_mm = gdk_screen_get_monitor_height_mm (gscreen, i);
+#endif
+      if (width_mm < 0)
+	width_mm = rec.width * mm_width_per_pixel + 0.5;
+      if (height_mm < 0)
+	height_mm = rec.height * mm_height_per_pixel + 0.5;
+      attributes = Fcons (Fcons (Qmm_size,
+				 x_create_size_alist (width_mm, height_mm)),
+			  attributes);
+
+#if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4)
+      gdk_screen_get_monitor_workarea (gscreen, i, &rec);
+      workarea = x_create_geometry_alist (rec.x, rec.y, rec.width, rec.height);
+#else
+      /* Emulate the behavior of GTK+ 3.4.  */
+      {
+	XRectangle workarea_r;
+
+	workarea = Qnil;
+	if (i == primary_monitor && x_get_net_workarea (dpyinfo, &workarea_r))
+	  {
+	    GdkRectangle work;
+
+	    work.x = workarea_r.x;
+	    work.y = workarea_r.y;
+	    work.width = workarea_r.width;
+	    work.height = workarea_r.height;
+	    if (gdk_rectangle_intersect (&rec, &work, &work))
+	      workarea = x_create_geometry_alist (work.x, work.y,
+						  work.width, work.height);
+	  }
+	if (NILP (workarea))
+	  workarea = geometry;
+      }
+#endif
+      attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+
+      attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+#if GTK_MAJOR_VERSION > 2 || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 14)
+      {
+        char *name = gdk_screen_get_monitor_plug_name (gscreen, i);
+        if (name)
+          attributes = Fcons (Fcons (Qname, make_string (name, strlen (name))),
+                              attributes);
+      }
+#endif
+
+      if (i == primary_monitor)
+	primary_monitor_attributes = attributes;
+      else
+	attributes_list = Fcons (attributes, attributes_list);
+    }
+
+  if (!NILP (primary_monitor_attributes))
+    attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+  unblock_input ();
+#else  /* not USE_GTK */
+
+  block_input ();
+  attributes_list = x_get_monitor_attributes (dpyinfo);
+  unblock_input ();
+
+#endif	/* not USE_GTK */
+
+  return attributes_list;
+}
+
 \f
 int
 x_pixel_width (register struct frame *f)
@@ -5701,6 +6299,11 @@
   DEFSYM (Qundefined_color, "undefined-color");
   DEFSYM (Qcompound_text, "compound-text");
   DEFSYM (Qcancel_timer, "cancel-timer");
+  DEFSYM (Qgeometry, "geometry");
+  DEFSYM (Qworkarea, "workarea");
+  DEFSYM (Qmm_size, "mm-size");
+  DEFSYM (Qframes, "frames");
+  DEFSYM (Qsource, "source");
   DEFSYM (Qfont_param, "font-parameter");
   /* This is the end of symbol initialization.  */
 
@@ -5864,6 +6467,7 @@
   defsubr (&Sx_display_visual_class);
   defsubr (&Sx_display_backing_store);
   defsubr (&Sx_display_save_under);
+  defsubr (&Sx_display_monitor_attributes_list);
   defsubr (&Sx_wm_set_size_hint);
   defsubr (&Sx_create_frame);
   defsubr (&Sx_open_connection);

=== modified file 'src/xterm.c'
--- src/xterm.c	2013-03-25 17:58:35 +0000
+++ src/xterm.c	2013-04-28 17:17:40 +0000
@@ -10251,6 +10251,8 @@
       { "_NET_WM_WINDOW_OPACITY", &dpyinfo->Xatom_net_wm_window_opacity },
       { "_NET_ACTIVE_WINDOW", &dpyinfo->Xatom_net_active_window },
       { "_NET_FRAME_EXTENTS", &dpyinfo->Xatom_net_frame_extents },
+      { "_NET_CURRENT_DESKTOP", &dpyinfo->Xatom_net_current_desktop },
+      { "_NET_WORKAREA", &dpyinfo->Xatom_net_workarea },
       /* Session management */
       { "SM_CLIENT_ID", &dpyinfo->Xatom_SM_CLIENT_ID },
       { "_XSETTINGS_SETTINGS", &dpyinfo->Xatom_xsettings_prop },

=== modified file 'src/xterm.h'
--- src/xterm.h	2013-04-07 04:41:19 +0000
+++ src/xterm.h	2013-04-28 17:17:40 +0000
@@ -346,7 +346,8 @@
   Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
     Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
     Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
-    Xatom_net_frame_extents;
+    Xatom_net_frame_extents,
+    Xatom_net_current_desktop, Xatom_net_workarea;
 
   /* XSettings atoms and windows.  */
   Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;


[-- Attachment #3: Type: text/plain, Size: 3 bytes --]





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

* Re: x-display-pixel-width/height inconsistency
  2013-05-01  9:58                               ` Jan Djärv
@ 2013-05-02  4:09                                 ` YAMAMOTO Mitsuharu
  2013-05-06  1:04                                   ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-02  4:09 UTC (permalink / raw)
  To: Jan Djärv; +Cc: emacs-devel

>>>>> On Wed, 1 May 2013 11:58:15 +0200, Jan Djärv <jan.h.d@swipnet.se> said:

>> This guess was not right.  GDK rejects XRandR in Xquartz and uses
>> Xinerama instead.  The distinction is made by comparing the output
>> name with "default".
>> 
>> in init_randr13 (gdkscreen-x11.c):
>> 
>> XRROutputInfo *output =
>> XRRGetOutputInfo (dpy, resources, resources->outputs[i]);
>> 
>> /* Non RandR1.2 X driver have output name "default" */
>> randr12_compat |= !g_strcmp0 (output->name, "default");

> I did not know that.  I've made adjustments for this in the patch, tested on XQuartz which indeed does not seem to have a 1.2-compatible driver.  Strange that.

> I also added name and source (the latter mostly for debugging) to the Lisp structure returned.
> I also check for XRRGetScreenResourcesCurrent in configure as that is a 1.3 version function.

I tried the patch for Xaw build with XQuartz 2.7.4 on OSX 10.8, and it
hit the following assertion failure:

  src/xfns.c:3989: Emacs fatal error: assertion failed: 0 <= (i) && (i) < ASIZE (monitor_frames)

  3981	  FOR_EACH_FRAME (rest, frame)
  3982	    {
  3983	      struct frame *f = XFRAME (frame);
  3984	
  3985	      if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
  3986		  && !EQ (frame, tip_frame))
  3987		{
  3988		  i = x_get_monitor_for_frame (f, monitors, n_monitors);
  3989		  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
  3990		}
  3991	    }

This is because XRRGetScreenResourcesCurrent returns the following
bogus value where the `noutput' member is 0.

  (gdb) p *resources
  $5 = {
    timestamp = 1653376136, 
    configTimestamp = 1653376136, 
    ncrtc = 0, 
    crtcs = 0x101457270, 
    noutput = 0, 
    outputs = 0x101457270, 
    nmode = 0, 
    modes = 0x101457270
  }

GDK also uses XRRGetScreenResourcesCurrent.  So, in the GDK code, what
actually distinguished XRandR in XQuartz from the other
implementationswas not the comparison of the output name with
"default", but the positiveness of the `noutput' member.

static gboolean
init_randr13 (GdkScreen *screen)
{
	:
  monitors = g_array_sized_new (FALSE, TRUE, sizeof (GdkX11Monitor),
                                resources->noutput);
	:
  x11_screen->n_monitors = monitors->len;
	:
  return x11_screen->n_monitors > 0;
}

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-02  4:09                                 ` YAMAMOTO Mitsuharu
@ 2013-05-06  1:04                                   ` YAMAMOTO Mitsuharu
  2013-05-06  1:55                                     ` Stefan Monnier
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-06  1:04 UTC (permalink / raw)
  To: emacs-devel; +Cc: Jan Djärv, Stefan Monnier

Jan and I are currently improving the patch for multi-monitor support
on X11 off the list.

Stefan, which should we use for the name of the primitive,
x-display-monitor-attributes-list or display-monitor-attributes-list ?
I thought your previous post below meant that the platform-specific
implementations (primitives) should be prefixed as x-*, w32-*, or
ns-*, and the main Lisp function without a prefix should dispatch to
them.  But what actually happened to display-usable-bounds was to name
an NS-specific implementation without a prefix.  So I'm confused.

  Actually, better *not* use an "x-" prefix for the main name.  I.e. name
  it "display-usable-bounds".  It's implementation may just check the
  display used by the selected frame and dispatch to
  x-display-usable-bounds,  w32-display-usable-bounds,
  mac-display-usable-bounds, ...
  (http://lists.gnu.org/archive/html/emacs-devel/2007-12/msg00166.html)

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-06  1:04                                   ` YAMAMOTO Mitsuharu
@ 2013-05-06  1:55                                     ` Stefan Monnier
  2013-05-06  6:15                                       ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Stefan Monnier @ 2013-05-06  1:55 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Jan Djärv, emacs-devel

> Jan and I are currently improving the patch for multi-monitor support
> on X11 off the list.

> Stefan, which should we use for the name of the primitive,
> x-display-monitor-attributes-list or display-monitor-attributes-list ?
> I thought your previous post below meant that the platform-specific
> implementations (primitives) should be prefixed as x-*, w32-*, or
> ns-*, and the main Lisp function without a prefix should dispatch to
> them.

Right, the main entry point should be display-monitor-attributes-list
and it should then dispatch to the right implementation.  This dispatch
can be done in Elisp (in which case you need to export x-<foo>,
ns-<foo>, ... to Elisp) or all in C, in which case there's no need for
x-<foo>, ns-<foo>, ...

> But what actually happened to display-usable-bounds was to name
> an NS-specific implementation without a prefix.

Sounds like a bug (tho as long as only NS provides this functionality,
it's probably a minor bug).


        Stefan




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

* Re: x-display-pixel-width/height inconsistency
  2013-05-06  1:55                                     ` Stefan Monnier
@ 2013-05-06  6:15                                       ` YAMAMOTO Mitsuharu
  2013-05-06 13:37                                         ` Stefan Monnier
  2013-05-08 10:46                                         ` YAMAMOTO Mitsuharu
  0 siblings, 2 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-06  6:15 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Jan Djärv, emacs-devel

>>>>> On Sun, 05 May 2013 21:55:15 -0400, Stefan Monnier <monnier@iro.umontreal.ca> said:

>> Stefan, which should we use for the name of the primitive,
>> x-display-monitor-attributes-list or
>> display-monitor-attributes-list ?  I thought your previous post
>> below meant that the platform-specific implementations (primitives)
>> should be prefixed as x-*, w32-*, or ns-*, and the main Lisp
>> function without a prefix should dispatch to them.

> Right, the main entry point should be
> display-monitor-attributes-list and it should then dispatch to the
> right implementation.  This dispatch can be done in Elisp (in which
> case you need to export x-<foo>, ns-<foo>, ... to Elisp) or all in
> C, in which case there's no need for x-<foo>, ns-<foo>, ...

Thanks for clarifying.  I added a Lisp-level dispatcher and moved most
of the documentation to it in the patch below.

>> But what actually happened to display-usable-bounds was to name an
>> NS-specific implementation without a prefix.

> Sounds like a bug (tho as long as only NS provides this
> functionality, it's probably a minor bug).

I think display-usable-bounds should be removed once all the
display-monitor-attributes-list work is done, because it is superseded
by the latter, only NS implementation is provided, it is not
documented in either NEWS or info, its argument convention does not
match with the other display-* functions on X11, and it actually gives
wrong results for non-primary monitors.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'configure.ac'
*** configure.ac	2013-04-26 19:31:09 +0000
--- configure.ac	2013-05-06 03:44:04 +0000
***************
*** 2814,2819 ****
--- 2814,2869 ----
  fi
  AC_SUBST(LIBXSM)
  
+ ### Use XRandr (-lXrandr) if available
+ HAVE_XRANDR=no
+ if test "${HAVE_X11}" = "yes"; then
+   XRANDR_REQUIRED=1.2.2
+   XRANDR_MODULES="xrandr >= $XRANDR_REQUIRED"
+   PKG_CHECK_MODULES(XRANDR, $XRANDR_MODULES, HAVE_XRANDR=yes, HAVE_XRANDR=no)
+   if test $HAVE_XRANDR = no; then
+     # Test old way in case pkg-config doesn't have it (older machines).
+     AC_CHECK_HEADER(X11/extensions/Xrandr.h,
+       [AC_CHECK_LIB(Xrandr, XRRQueryExtension, HAVE_XRANDR=yes)])
+     if test $HAVE_XRANDR = yes; then
+       XRANDR_LIBS=-lXrandr
+       AC_SUBST(XRANDR_LIBS)
+     fi
+   fi
+   if test $HAVE_XRANDR = yes; then
+     SAVE_CFLAGS="$CFLAGS"
+     SAVE_LIBS="$LIBS"
+     CFLAGS="$XRANDR_CFLAGS $CFLAGS"
+     LIBS="$XRANDR_LIBS $LIBS"
+     AC_CHECK_FUNCS(XRRGetOutputPrimary XRRGetScreenResourcesCurrent)
+     CFLAGS="$SAVE_CFLAGS"
+     LIBS="$SAVE_LIBS"
+ 
+     AC_DEFINE(HAVE_XRANDR, 1, [Define to 1 if you have the XRandr extension.])
+   fi
+ fi
+ 
+ ### Use Xinerama (-lXinerama) if available
+ HAVE_XINERAMA=no
+ if test "${HAVE_X11}" = "yes"; then
+   XINERAMA_REQUIRED=1.0.2
+   XINERAMA_MODULES="xinerama >= $XINERAMA_REQUIRED"
+   PKG_CHECK_MODULES(XINERAMA, $XINERAMA_MODULES, HAVE_XINERAMA=yes,
+                     HAVE_XINERAMA=no)
+   if test $HAVE_XINERAMA = no; then
+     # Test old way in case pkg-config doesn't have it (older machines).
+     AC_CHECK_HEADER(X11/extensions/Xinerama.h,
+       [AC_CHECK_LIB(Xinerama, XineramaQueryExtension, HAVE_XINERAMA=yes)])
+     if test $HAVE_XINERAMA = yes; then
+       XINERAMA_LIBS=-lXinerama
+       AC_SUBST(XINERAMA_LIBS)
+     fi
+   fi
+   if test $HAVE_XINERAMA = yes; then
+     AC_DEFINE(HAVE_XINERAMA, 1, [Define to 1 if you have the Xinerama extension.])
+   fi
+ fi
+ 
+ 
  ### Use libxml (-lxml2) if available
  HAVE_LIBXML2=no
  if test "${with_xml2}" != "no"; then

=== modified file 'lisp/frame.el'
*** lisp/frame.el	2013-04-06 14:06:39 +0000
--- lisp/frame.el	2013-05-06 05:43:47 +0000
***************
*** 1256,1261 ****
--- 1256,1278 ----
      (unless (memq vert '(left right nil))
        (setq vert default-frame-scroll-bars))
      (cons vert hor)))
+ 
+ (defun frame-monitor-attributes (&optional frame)
+   "Return the attributes of the physical monitor dominating FRAME.
+ If FRAME is omitted, describe the currently selected frame.
+ 
+ A frame is dominated by a physical monitor when either the
+ largest area of the frame resides in the monitor, or the monitor
+ is the closest to the frame if the frame does not intersect any
+ physical monitors.
+ 
+ See `display-monitor-attributes-list' for the list of attribute
+ keys and their meanings."
+   (or frame (setq frame (selected-frame)))
+   (cl-loop for attributes in (display-monitor-attributes-list frame)
+ 	   for frames = (cdr (assq 'frames attributes))
+ 	   if (memq frame frames) return attributes))
+ 
  \f
  ;;;; Frame/display capabilities.
  (defun selected-terminal ()
***************
*** 1476,1481 ****
--- 1493,1542 ----
       (t
        'static-gray))))
  
+ (declare-function x-display-monitor-attributes-list "xfns.c"
+ 		  (&optional terminal))
+ 
+ (defun display-monitor-attributes-list (&optional display)
+   "Return a list of physical monitor attributes on DISPLAY.
+ Each element of the list represents the attributes of each
+ physical monitor.  The first element corresponds to the primary
+ monitor.
+ 
+ Attributes for a physical monitor is represented as an alist of
+ attribute keys and values as follows:
+ 
+  geometry -- Position and size in pixels in the form of
+ 	     (X Y WIDTH HEIGHT)
+  workarea -- Position and size of the workarea in pixels in the
+ 	     form of (X Y WIDTH HEIGHT)
+  mm-size  -- Width and height in millimeters in the form of
+  	     (WIDTH HEIGHT)
+  frames   -- List of frames dominated by the physical monitor
+  name (*) -- Name of the physical monitor as a string
+ 
+ where X, Y, WIDTH, and HEIGHT are integers.  Keys labeled
+ with (*) are optional.
+ 
+ A frame is dominated by a physical monitor when either the
+ largest area of the frame resides in the monitor, or the monitor
+ is the closest to the frame if the frame does not intersect any
+ physical monitors.  Every non-tip frame (including invisible one)
+ in a graphical display is dominated by exactly one physical
+ monitor at a time, though it can span multiple (or no) physical
+ monitors."
+   (let ((frame-type (framep-on-display display)))
+     (cond
+      ((eq frame-type 'x)
+       (x-display-monitor-attributes-list display))
+      (t
+       (let ((geometry (list 0 0 (display-pixel-width display)
+ 			    (display-pixel-height display))))
+ 	`(((geometry . ,geometry)
+ 	   (workarea . ,geometry)
+ 	   (mm-size . (,(display-mm-width display)
+ 		       ,(display-mm-height display)))
+ 	   (frames . ,(frames-on-display-list display)))))))))
+ 
  \f
  ;;;; Frame geometry values
  

=== modified file 'src/xfns.c'
*** src/xfns.c	2013-04-07 04:41:19 +0000
--- src/xfns.c	2013-05-06 05:06:34 +0000
***************
*** 59,64 ****
--- 59,71 ----
  
  #include "xsettings.h"
  
+ #ifdef HAVE_XRANDR
+ #include <X11/extensions/Xrandr.h>
+ #endif
+ #ifdef HAVE_XINERAMA
+ #include <X11/extensions/Xinerama.h>
+ #endif
+ 
  #ifdef USE_GTK
  #include "gtkutil.h"
  #endif
***************
*** 126,131 ****
--- 133,139 ----
  static Lisp_Object Qsuppress_icon;
  static Lisp_Object Qundefined_color;
  static Lisp_Object Qcompound_text, Qcancel_timer;
+ static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource;
  Lisp_Object Qfont_param;
  
  #ifdef GLYPH_DEBUG
***************
*** 3791,3796 ****
--- 3799,4357 ----
    else
      return Qnil;
  }
+ 
+ /* Store the geometry of the workarea on display DPYINFO into *RECT.
+    Return false if and only if the workarea information cannot be
+    obtained via the _NET_WORKAREA root window property.  */
+ 
+ static bool
+ x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect)
+ {
+   Display *dpy = dpyinfo->display;
+   long offset, max_len;
+   Atom target_type, actual_type;
+   unsigned long actual_size, bytes_remaining;
+   int rc, actual_format;
+   unsigned char *tmp_data = NULL;
+   bool result = false;
+ 
+   x_catch_errors (dpy);
+   offset = 0;
+   max_len = 1;
+   target_type = XA_CARDINAL;
+   rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+ 			   dpyinfo->Xatom_net_current_desktop,
+ 			   offset, max_len, False, target_type,
+ 			   &actual_type, &actual_format, &actual_size,
+ 			   &bytes_remaining, &tmp_data);
+   if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+       && actual_format == 32 && actual_size == max_len)
+     {
+       long current_desktop = ((long *) tmp_data)[0];
+ 
+       XFree (tmp_data);
+       tmp_data = NULL;
+ 
+       offset = 4 * current_desktop;
+       max_len = 4;
+       rc = XGetWindowProperty (dpy, dpyinfo->root_window,
+ 			       dpyinfo->Xatom_net_workarea,
+ 			       offset, max_len, False, target_type,
+ 			       &actual_type, &actual_format, &actual_size,
+ 			       &bytes_remaining, &tmp_data);
+       if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy)
+ 	  && actual_format == 32 && actual_size == max_len)
+ 	{
+ 	  long *values = (long *) tmp_data;
+ 
+ 	  rect->x = values[0];
+ 	  rect->y = values[1];
+ 	  rect->width = values[2];
+ 	  rect->height = values[3];
+ 
+ 	  XFree (tmp_data);
+ 	  tmp_data = NULL;
+ 
+ 	  result = true;
+ 	}
+     }
+   if (tmp_data)
+     XFree (tmp_data);
+   x_uncatch_errors ();
+ 
+   return result;
+ }
+ 
+ struct MonitorInfo {
+   XRectangle geom, work;
+   int mm_width, mm_height;
+   char *name;
+ };
+ 
+ static void
+ free_monitors (struct MonitorInfo *monitors, int n_monitors)
+ {
+   int i;
+   for (i = 0; i < n_monitors; ++i)
+     xfree (monitors[i].name);
+   xfree (monitors);
+ }
+ 
+ 
+ /* Return monitor number where F is "most" or closest to.  */
+ static int
+ x_get_monitor_for_frame (struct frame *f,
+                          struct MonitorInfo *monitors,
+                          int n_monitors)
+ {
+   XRectangle frect;
+   int area = 0, dist = -1;
+   int best_area = -1, best_dist = -1;
+   int i;
+ 
+   if (n_monitors == 1) return 0;
+   frect.x = f->left_pos;
+   frect.y = f->top_pos;
+   frect.width = FRAME_PIXEL_WIDTH (f);
+   frect.height = FRAME_PIXEL_HEIGHT (f);
+ 
+   for (i = 0; i < n_monitors; ++i)
+     {
+       struct MonitorInfo *mi = &monitors[i];
+       XRectangle res;
+       int a = 0;
+ 
+       if (mi->geom.width == 0) continue;
+ 
+       if (x_intersect_rectangles (&mi->geom, &frect, &res))
+         {
+           a = res.width * res.height;
+           if (a > area) {
+             area = a;
+             best_area = i;
+           }
+         }
+ 
+       if (a == 0 && area == 0)
+         {
+           int dx, dy, d;
+           if (frect.x + frect.width < mi->geom.x)
+             dx = mi->geom.x - frect.x + frect.width;
+           else if (frect.x > mi->geom.x + mi->geom.width)
+             dx = frect.x - mi->geom.x + mi->geom.width;
+           else
+             dx = 0;
+           if (frect.y + frect.height < mi->geom.y)
+             dy = mi->geom.y - frect.y + frect.height;
+           else if (frect.y > mi->geom.y + mi->geom.height)
+             dy = frect.y - mi->geom.y + mi->geom.height;
+           else
+             dy = 0;
+ 
+           d = dx*dx + dy*dy;
+           if (dist == -1 || dist > d)
+             {
+               dist = d;
+               best_dist = i;
+             }
+         }
+     }
+ 
+   return best_area != -1 ? best_area : (best_dist != -1 ? best_dist : 0);
+ }
+ 
+ static Lisp_Object
+ x_make_monitor_attribute_list (struct MonitorInfo *monitors,
+                                int n_monitors,
+                                int primary_monitor,
+                                struct x_display_info *dpyinfo,
+                                const char *source)
+ {
+   Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+   Lisp_Object frame, rest, attributes_list = Qnil;
+   Lisp_Object primary_monitor_attributes = Qnil;
+   int i;
+ 
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	{
+ 	  i = x_get_monitor_for_frame (f, monitors, n_monitors);
+ 	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+ 	}
+     }
+ 
+   for (i = 0; i < n_monitors; ++i)
+     {
+       Lisp_Object geometry, workarea, attributes = Qnil;
+       struct MonitorInfo *mi = &monitors[i];
+ 
+       if (mi->geom.width == 0) continue;
+ 
+       workarea = list4i (mi->work.x, mi->work.y,
+ 			 mi->work.width, mi->work.height);
+       geometry = list4i (mi->geom.x, mi->geom.y,
+ 			 mi->geom.width, mi->geom.height);
+       attributes = Fcons (Fcons (Qsource,
+                                  make_string (source, strlen (source))),
+                           attributes);
+       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+ 			  attributes);
+       attributes = Fcons (Fcons (Qmm_size,
+                                  list2i (mi->mm_width, mi->mm_height)),
+                           attributes);
+       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+       if (mi->name)
+         attributes = Fcons (Fcons (Qname, make_string (mi->name,
+                                                        strlen (mi->name))),
+                             attributes);
+ 
+       if (i == primary_monitor)
+         primary_monitor_attributes = attributes;
+       else
+         attributes_list = Fcons (attributes, attributes_list);
+     }
+ 
+   if (!NILP (primary_monitor_attributes))
+     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+   return attributes_list;
+ }
+ 
+ static Lisp_Object
+ x_get_monitor_attributes_fallback (struct x_display_info *dpyinfo)
+ {
+   struct MonitorInfo monitor;
+   int width_mm, height_mm;
+   XRectangle workarea_r;
+ 
+   /* Fallback: treat (possibly) multiple physical monitors as if they
+      formed a single monitor as a whole.  This should provide a
+      consistent result at least on single monitor environments.  */
+   monitor.geom.x = monitor.geom.y = 0;
+   monitor.geom.width = x_display_pixel_width (dpyinfo);
+   monitor.geom.height = x_display_pixel_height (dpyinfo);
+   monitor.mm_width = WidthMMOfScreen (dpyinfo->screen);
+   monitor.mm_height = HeightMMOfScreen (dpyinfo->screen);
+   monitor.name = xstrdup ("combined screen");
+ 
+   if (x_get_net_workarea (dpyinfo, &workarea_r))
+     monitor.work = workarea_r;
+   else
+     monitor.work = monitor.geom;
+   return x_make_monitor_attribute_list (&monitor, 1, 0, dpyinfo, "fallback");
+ }
+ 
+ 
+ #ifdef HAVE_XINERAMA
+ static Lisp_Object
+ x_get_monitor_attributes_xinerama (struct x_display_info *dpyinfo)
+ {
+   int n_monitors, i;
+   Lisp_Object attributes_list = Qnil;
+   Display *dpy = dpyinfo->display;
+   XineramaScreenInfo *info = XineramaQueryScreens (dpy, &n_monitors);
+   struct MonitorInfo *monitors;
+   float mm_width_per_pixel, mm_height_per_pixel;
+ 
+   if (! info || n_monitors == 0)
+     {
+       if (info)
+ 	XFree (info);
+       return attributes_list;
+     }
+ 
+   mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
+ 			/ x_display_pixel_width (dpyinfo));
+   mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
+ 			 / x_display_pixel_height (dpyinfo));
+   monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors));
+   for (i = 0; i < n_monitors; ++i)
+     {
+       struct MonitorInfo *mi = &monitors[i];
+       XRectangle workarea_r;
+ 
+       mi->geom.x = info[i].x_org;
+       mi->geom.y = info[i].y_org;
+       mi->geom.width = info[i].width;
+       mi->geom.height = info[i].height;
+       mi->mm_width = mi->geom.width * mm_width_per_pixel + 0.5;
+       mi->mm_height = mi->geom.height * mm_height_per_pixel + 0.5;
+       mi->name = 0;
+ 
+       /* Xinerama usually have primary monitor first, just use that.  */
+       if (i == 0 && x_get_net_workarea (dpyinfo, &workarea_r))
+ 	{
+ 	  mi->work = workarea_r;
+ 	  if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work))
+ 	    mi->work = mi->geom;
+ 	}
+       else
+ 	mi->work = mi->geom;
+     }
+   XFree (info);
+ 
+   attributes_list = x_make_monitor_attribute_list (monitors,
+                                                    n_monitors,
+                                                    0,
+                                                    dpyinfo,
+                                                    "Xinerama");
+   free_monitors (monitors, n_monitors);
+   return attributes_list;
+ }
+ #endif /* HAVE_XINERAMA */
+ 
+ 
+ #ifdef HAVE_XRANDR
+ static Lisp_Object
+ x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo)
+ {
+   Lisp_Object attributes_list = Qnil;
+   XRRScreenResources *resources;
+   Display *dpy = dpyinfo->display;
+   int i, n_monitors, primary = -1;
+   RROutput pxid = None;
+   struct MonitorInfo *monitors;
+ 
+ #ifdef HAVE_XRRGETSCREENRESOURCESCURRENT
+   resources = XRRGetScreenResourcesCurrent (dpy, dpyinfo->root_window);
+ #else
+   resources = XRRGetScreenResources (dpy, dpyinfo->root_window);
+ #endif
+   if (! resources || resources->noutput == 0)
+     {
+       if (resources)
+ 	XRRFreeScreenResources (resources);
+       return Qnil;
+     }
+   n_monitors = resources->noutput;
+   monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors));
+ 
+ #ifdef HAVE_XRRGETOUTPUTPRIMARY
+   pxid = XRRGetOutputPrimary (dpy, dpyinfo->root_window);
+ #endif
+ 
+   for (i = 0; i < n_monitors; ++i)
+     {
+       XRROutputInfo *info = XRRGetOutputInfo (dpy, resources,
+                                               resources->outputs[i]);
+       Connection conn = info ? info->connection : RR_Disconnected;
+       RRCrtc id = info ? info->crtc : None;
+ 
+       if (strcmp (info->name, "default") == 0)
+         {
+           /* Non XRandr 1.2 driver, does not give useful data.  */
+ 	  XRRFreeOutputInfo (info);
+ 	  XRRFreeScreenResources (resources);
+           free_monitors (monitors, n_monitors);
+           return Qnil;
+         }
+ 
+       if (conn != RR_Disconnected && id != None)
+         {
+           XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, id);
+           struct MonitorInfo *mi = &monitors[i];
+           XRectangle workarea_r;
+ 
+           if (! crtc)
+ 	    {
+ 	      XRRFreeOutputInfo (info);
+ 	      continue;
+ 	    }
+ 
+           mi->geom.x = crtc->x;
+           mi->geom.y = crtc->y;
+           mi->geom.width = crtc->width;
+           mi->geom.height = crtc->height;
+           mi->mm_width = info->mm_width;
+           mi->mm_height = info->mm_height;
+           mi->name = xstrdup (info->name);
+ 
+           if (pxid != None && pxid == resources->outputs[i])
+             primary = i;
+           else if (primary == -1 && strcmp (info->name, "LVDS") == 0)
+             primary = i;
+ 
+           if (i == primary && x_get_net_workarea (dpyinfo, &workarea_r))
+             {
+               mi->work= workarea_r;
+               if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work))
+                 mi->work = mi->geom;
+             }
+           else
+             mi->work = mi->geom;
+ 
+           XRRFreeCrtcInfo (crtc);
+         }
+       XRRFreeOutputInfo (info);
+     }
+   XRRFreeScreenResources (resources);
+ 
+   attributes_list = x_make_monitor_attribute_list (monitors,
+                                                    n_monitors,
+                                                    primary,
+                                                    dpyinfo,
+                                                    "XRandr");
+   free_monitors (monitors, n_monitors);
+   return attributes_list;
+ }
+ #endif /* HAVE_XRANDR */
+ 
+ static Lisp_Object
+ x_get_monitor_attributes (struct x_display_info *dpyinfo)
+ {
+   Lisp_Object attributes_list = Qnil;
+   Display *dpy = dpyinfo->display;
+ 
+ #ifdef HAVE_XRANDR
+   int xrr_event_base, xrr_error_base;
+   bool xrr_ok = false;
+   xrr_ok = XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base);
+   if (xrr_ok)
+     {
+       int xrr_major, xrr_minor;
+       XRRQueryVersion (dpy, &xrr_major, &xrr_minor);
+       xrr_ok = (xrr_major == 1 && xrr_minor >= 2) || xrr_major > 1;
+     }
+ 
+   if (xrr_ok)
+     attributes_list = x_get_monitor_attributes_xrandr (dpyinfo);
+ #endif /* HAVE_XRANDR */
+ 
+ #ifdef HAVE_XINERAMA
+   if (NILP (attributes_list))
+     {
+       int xin_event_base, xin_error_base;
+       bool xin_ok = false;
+       xin_ok = XineramaQueryExtension (dpy, &xin_event_base, &xin_error_base);
+       if (xin_ok && XineramaIsActive (dpy))
+         attributes_list = x_get_monitor_attributes_xinerama (dpyinfo);
+     }
+ #endif /* HAVE_XINERAMA */
+ 
+   if (NILP (attributes_list))
+     attributes_list = x_get_monitor_attributes_fallback (dpyinfo);
+ 
+   return attributes_list;
+ }
+ 
+ DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list,
+        Sx_display_monitor_attributes_list,
+        0, 1, 0,
+        doc: /* Return a list of physical monitor attributes on the X display TERMINAL.
+ 
+ The optional argument TERMINAL specifies which display to ask about.
+ TERMINAL should be a terminal object, a frame or a display name (a string).
+ If omitted or nil, that stands for the selected frame's display.
+ 
+ Internal use only, use `display-monitor-attributes-list' instead.  */)
+   (Lisp_Object terminal)
+ {
+   struct x_display_info *dpyinfo = check_x_display_info (terminal);
+   Lisp_Object attributes_list = Qnil;
+ 
+ #ifdef USE_GTK
+   float mm_width_per_pixel, mm_height_per_pixel;
+   GdkDisplay *gdpy;
+   GdkScreen *gscreen;
+   gint primary_monitor = 0, n_monitors, i;
+   Lisp_Object primary_monitor_attributes = Qnil;
+   Lisp_Object monitor_frames, rest, frame;
+   static const char *source = "Gdk";
+ 
+   block_input ();
+   mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen)
+ 			/ x_display_pixel_width (dpyinfo));
+   mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen)
+ 			 / x_display_pixel_height (dpyinfo));
+   gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display);
+   gscreen = gdk_display_get_default_screen (gdpy);
+ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 20
+   primary_monitor = gdk_screen_get_primary_monitor (gscreen);
+ #endif
+   n_monitors = gdk_screen_get_n_monitors (gscreen);
+   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	{
+ 	  GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f));
+ 
+ 	  i = gdk_screen_get_monitor_at_window (gscreen, gwin);
+ 	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+ 	}
+     }
+ 
+   i = n_monitors;
+   while (i-- > 0)
+     {
+       Lisp_Object geometry, workarea, attributes = Qnil;
+       gint width_mm = -1, height_mm = -1;
+       GdkRectangle rec;
+ 
+       attributes = Fcons (Fcons (Qsource,
+                                  make_string (source, strlen (source))),
+                           attributes);
+       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+ 			  attributes);
+ 
+       gdk_screen_get_monitor_geometry (gscreen, i, &rec);
+       geometry = list4i (rec.x, rec.y, rec.width, rec.height);
+ 
+ #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 14
+       width_mm = gdk_screen_get_monitor_width_mm (gscreen, i);
+       height_mm = gdk_screen_get_monitor_height_mm (gscreen, i);
+ #endif
+       if (width_mm < 0)
+ 	width_mm = rec.width * mm_width_per_pixel + 0.5;
+       if (height_mm < 0)
+ 	height_mm = rec.height * mm_height_per_pixel + 0.5;
+       attributes = Fcons (Fcons (Qmm_size,
+ 				 list2i (width_mm, height_mm)),
+ 			  attributes);
+ 
+ #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4)
+       gdk_screen_get_monitor_workarea (gscreen, i, &rec);
+       workarea = list4i (rec.x, rec.y, rec.width, rec.height);
+ #else
+       /* Emulate the behavior of GTK+ 3.4.  */
+       {
+ 	XRectangle workarea_r;
+ 
+ 	workarea = Qnil;
+ 	if (i == primary_monitor && x_get_net_workarea (dpyinfo, &workarea_r))
+ 	  {
+ 	    GdkRectangle work;
+ 
+ 	    work.x = workarea_r.x;
+ 	    work.y = workarea_r.y;
+ 	    work.width = workarea_r.width;
+ 	    work.height = workarea_r.height;
+ 	    if (gdk_rectangle_intersect (&rec, &work, &work))
+ 	      workarea = list4i (work.x, work.y, work.width, work.height);
+ 	  }
+ 	if (NILP (workarea))
+ 	  workarea = geometry;
+       }
+ #endif
+       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ #if GTK_MAJOR_VERSION > 2 || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 14)
+       {
+         char *name = gdk_screen_get_monitor_plug_name (gscreen, i);
+         if (name)
+           attributes = Fcons (Fcons (Qname, make_string (name, strlen (name))),
+                               attributes);
+       }
+ #endif
+ 
+       if (i == primary_monitor)
+ 	primary_monitor_attributes = attributes;
+       else
+ 	attributes_list = Fcons (attributes, attributes_list);
+     }
+ 
+   if (!NILP (primary_monitor_attributes))
+     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+   unblock_input ();
+ #else  /* not USE_GTK */
+ 
+   block_input ();
+   attributes_list = x_get_monitor_attributes (dpyinfo);
+   unblock_input ();
+ 
+ #endif	/* not USE_GTK */
+ 
+   return attributes_list;
+ }
+ 
  \f
  int
  x_pixel_width (register struct frame *f)
***************
*** 5701,5706 ****
--- 6262,6272 ----
    DEFSYM (Qundefined_color, "undefined-color");
    DEFSYM (Qcompound_text, "compound-text");
    DEFSYM (Qcancel_timer, "cancel-timer");
+   DEFSYM (Qgeometry, "geometry");
+   DEFSYM (Qworkarea, "workarea");
+   DEFSYM (Qmm_size, "mm-size");
+   DEFSYM (Qframes, "frames");
+   DEFSYM (Qsource, "source");
    DEFSYM (Qfont_param, "font-parameter");
    /* This is the end of symbol initialization.  */
  
***************
*** 5864,5869 ****
--- 6430,6436 ----
    defsubr (&Sx_display_visual_class);
    defsubr (&Sx_display_backing_store);
    defsubr (&Sx_display_save_under);
+   defsubr (&Sx_display_monitor_attributes_list);
    defsubr (&Sx_wm_set_size_hint);
    defsubr (&Sx_create_frame);
    defsubr (&Sx_open_connection);

=== modified file 'src/xterm.c'
*** src/xterm.c	2013-03-25 17:58:35 +0000
--- src/xterm.c	2013-05-03 05:27:11 +0000
***************
*** 10251,10256 ****
--- 10251,10258 ----
        { "_NET_WM_WINDOW_OPACITY", &dpyinfo->Xatom_net_wm_window_opacity },
        { "_NET_ACTIVE_WINDOW", &dpyinfo->Xatom_net_active_window },
        { "_NET_FRAME_EXTENTS", &dpyinfo->Xatom_net_frame_extents },
+       { "_NET_CURRENT_DESKTOP", &dpyinfo->Xatom_net_current_desktop },
+       { "_NET_WORKAREA", &dpyinfo->Xatom_net_workarea },
        /* Session management */
        { "SM_CLIENT_ID", &dpyinfo->Xatom_SM_CLIENT_ID },
        { "_XSETTINGS_SETTINGS", &dpyinfo->Xatom_xsettings_prop },

=== modified file 'src/xterm.h'
*** src/xterm.h	2013-04-07 04:41:19 +0000
--- src/xterm.h	2013-05-03 05:27:11 +0000
***************
*** 346,352 ****
    Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
      Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
      Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
!     Xatom_net_frame_extents;
  
    /* XSettings atoms and windows.  */
    Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;
--- 346,353 ----
    Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen,
      Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert,
      Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden,
!     Xatom_net_frame_extents,
!     Xatom_net_current_desktop, Xatom_net_workarea;
  
    /* XSettings atoms and windows.  */
    Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr;




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

* Re: x-display-pixel-width/height inconsistency
  2013-05-06  6:15                                       ` YAMAMOTO Mitsuharu
@ 2013-05-06 13:37                                         ` Stefan Monnier
  2013-05-08 10:46                                         ` YAMAMOTO Mitsuharu
  1 sibling, 0 replies; 97+ messages in thread
From: Stefan Monnier @ 2013-05-06 13:37 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Jan Djärv, emacs-devel

> I think display-usable-bounds should be removed once all the
> display-monitor-attributes-list work is done, because it is superseded
> by the latter, only NS implementation is provided, it is not
> documented in either NEWS or info, its argument convention does not
> match with the other display-* functions on X11, and it actually gives
> wrong results for non-primary monitors.

Fair enough.


        Stefan



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-06  6:15                                       ` YAMAMOTO Mitsuharu
  2013-05-06 13:37                                         ` Stefan Monnier
@ 2013-05-08 10:46                                         ` YAMAMOTO Mitsuharu
  2013-05-08 11:24                                           ` YAMAMOTO Mitsuharu
  2013-05-08 17:41                                           ` Eli Zaretskii
  1 sibling, 2 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-08 10:46 UTC (permalink / raw)
  To: emacs-devel

I also tried implementing a W32 version of multi-monitor support, but
I can't test it (I didn't even compile, actually).  Please test it.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'lisp/frame.el'
*** lisp/frame.el	2013-05-07 01:12:22 +0000
--- lisp/frame.el	2013-05-08 10:10:09 +0000
***************
*** 1365,1371 ****
  
  (defun display-pixel-height (&optional display)
    "Return the height of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
--- 1365,1375 ----
  
  (defun display-pixel-height (&optional display)
    "Return the height of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the pixel height for all physical monitors associated
! with DISPLAY.  To get information for each physical monitor, use
! `display-monitor-attributes-list'."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
***************
*** 1377,1383 ****
  
  (defun display-pixel-width (&optional display)
    "Return the width of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
--- 1381,1391 ----
  
  (defun display-pixel-width (&optional display)
    "Return the width of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the pixel width for all physical monitors associated
! with DISPLAY.  To get information for each physical monitor, use
! `display-monitor-attributes-list'."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
***************
*** 1408,1414 ****
  (defun display-mm-height (&optional display)
    "Return the height of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cddr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
--- 1416,1426 ----
  (defun display-mm-height (&optional display)
    "Return the height of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the height in millimeters for all physical monitors
! associated with DISPLAY.  To get information for each physical
! monitor, use `display-monitor-attributes-list'."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cddr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
***************
*** 1420,1426 ****
  (defun display-mm-width (&optional display)
    "Return the width of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cadr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
--- 1432,1442 ----
  (defun display-mm-width (&optional display)
    "Return the width of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the width in millimeters for all physical monitors
! associated with DISPLAY.  To get information for each physical
! monitor, use `display-monitor-attributes-list'."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cadr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
***************
*** 1495,1500 ****
--- 1511,1518 ----
  
  (declare-function x-display-monitor-attributes-list "xfns.c"
  		  (&optional terminal))
+ (declare-function w32-display-monitor-attributes-list "w32fns.c"
+ 		  (&optional display))
  
  (defun display-monitor-attributes-list (&optional display)
    "Return a list of physical monitor attributes on DISPLAY.
***************
*** 1528,1533 ****
--- 1546,1553 ----
      (cond
       ((eq frame-type 'x)
        (x-display-monitor-attributes-list display))
+      ((eq frame-type 'w32)
+       (w32-display-monitor-attributes-list display))
       (t
        (let ((geometry (list 0 0 (display-pixel-width display)
  			    (display-pixel-height display))))

=== modified file 'src/w32fns.c'
*** src/w32fns.c	2013-05-04 10:19:13 +0000
--- src/w32fns.c	2013-05-08 10:32:32 +0000
***************
*** 106,111 ****
--- 106,112 ----
  Lisp_Object Qctrl;
  Lisp_Object Qcontrol;
  Lisp_Object Qshift;
+ static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes;
  
  
  /* Prefix for system colors.  */
***************
*** 131,136 ****
--- 132,146 ----
  #ifndef MONITOR_DEFAULT_TO_NEAREST
  #define MONITOR_DEFAULT_TO_NEAREST 2
  #endif
+ #ifndef MONITORINFOF_PRIMARY
+ #define MONITORINFOF_PRIMARY 1
+ #endif
+ #ifndef SM_XVIRTUALSCREEN
+ #define SM_XVIRTUALSCREEN 76
+ #endif
+ #ifndef SM_YVIRTUALSCREEN
+ #define SM_YVIRTUALSCREEN 77
+ #endif
  /* MinGW headers define MONITORINFO unconditionally, but MSVC ones don't.
     To avoid a compile error on one or the other, redefine with a new name.  */
  struct MONITOR_INFO
***************
*** 141,146 ****
--- 151,168 ----
      DWORD   dwFlags;
  };
  
+ #ifndef CCHDEVICENAME
+ #define CCHDEVICENAME 32
+ #endif
+ struct MONITOR_INFO_EX
+ {
+     DWORD   cbSize;
+     RECT    rcMonitor;
+     RECT    rcWork;
+     DWORD   dwFlags;
+     char    szDevice[CCHDEVICENAME];
+ };
+ 
  /* Reportedly, MSVC does not have this in its headers.  */
  #if defined (_MSC_VER) && _WIN32_WINNT < 0x0500
  DECLARE_HANDLE(HMONITOR);
***************
*** 159,164 ****
--- 181,190 ----
    (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
  typedef HMONITOR (WINAPI * MonitorFromWindow_Proc)
    (IN HWND hwnd, IN DWORD dwFlags);
+ typedef BOOL CALLBACK (* MonitorEnum_Proc)
+   (IN HMONITOR monitor, IN HDC hdc, IN RECT *rcMonitor, IN LPARAM dwData);
+ typedef BOOL (WINAPI * EnumDisplayMonitors_Proc)
+   (IN HDC hdc, IN RECT *rcClip, IN MonitorEnum_Proc fnEnum, IN LPARAM dwData);
  
  TrackMouseEvent_Proc track_mouse_event_fn = NULL;
  ImmGetCompositionString_Proc get_composition_string_fn = NULL;
***************
*** 168,173 ****
--- 194,200 ----
  MonitorFromPoint_Proc monitor_from_point_fn = NULL;
  GetMonitorInfo_Proc get_monitor_info_fn = NULL;
  MonitorFromWindow_Proc monitor_from_window_fn = NULL;
+ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
  
  #ifdef NTGUI_UNICODE
  #define unicode_append_menu AppendMenuW
***************
*** 4656,4662 ****
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4683,4693 ----
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel width for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4669,4675 ****
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4700,4710 ----
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel height for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4761,4801 ****
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   int cap;
  
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, VERTSIZE);
! 
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
- 
    HDC hdc;
!   int cap;
! 
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, HORZSIZE);
  
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
--- 4796,4841 ----
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the height in millimeters for
! all physical monitors associated with DISPLAY.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
! 		  / GetDeviceCaps (hdc, VERTRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_height (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the width in millimeters for
! all physical monitors associated with TERMINAL.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
! 		  / GetDeviceCaps (hdc, HORZRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_width (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
***************
*** 4847,4852 ****
--- 4887,5078 ----
    return Qnil;
  }
  
+ static BOOL CALLBACK
+ w32_monitor_enum (HMONITOR monitor, HDC hdc, RECT *rcMonitor, LPARAM dwData)
+ {
+   Lisp_Object *monitor_list = (Lisp_Object *) dwData;
+ 
+   *monitor_list = Fcons (make_save_pointer (monitor), *monitor_list);
+ 
+   return TRUE;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list (void)
+ {
+   Lisp_Object attributes_list = Qnil, primary_monitor_attributes = Qnil;
+   Lisp_Object monitor_list, monitor_frames, rest, frame;
+   int i, n_monitors;
+   HMONITOR *monitors;
+ 
+   if (!(enum_display_monitors_fn && get_monitor_info_fn
+ 	&& monitor_from_window_fn))
+     return Qnil;
+ 
+   if (!enum_display_monitors_fn (NULL, NULL, w32_monitor_enum, &monitor_list)
+       || NILP (monitor_list))
+     return Qnil;
+ 
+   n_monitors = 0;
+   for (rest = monitor_list; CONSP (rest); rest = XCDR (rest))
+     n_monitors++;
+ 
+   monitors = xmalloc (n_monitors * sizeof (*monitors));
+   for (i = 0; i < n_monitors; i++)
+     {
+       monitors[i] = XSAVE_POINTER (XCAR (monitor_list), 0);
+       monitor_list = XCDR (monitor_list);
+     }
+ 
+   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	{
+ 	  HMONITOR monitor =
+ 	    monitor_from_window_fn (FRAME_W32_WINDOW (f),
+ 				    MONITOR_DEFAULT_TO_NEAREST);
+ 
+ 	  for (i = 0; i < n_monitors; i++)
+ 	    if (monitors[i] == monitor)
+ 	      break;
+ 
+ 	  ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+ 	}
+     }
+ 
+   for (i = 0; i < n_monitors; i++)
+     {
+       Lisp_Object geometry, workarea, name, attributes = Qnil;
+       HDC hdc;
+       int width_mm, height_mm;
+       struct MONITOR_INFO_EX mi;
+ 
+       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+ 			  attributes);
+ 
+       mi.cbSize = sizeof (mi);
+       get_monitor_info_fn (monitors[i], (struct MONITOR_INFO *) &mi);
+ 
+       name = make_unibyte_string (mi.szDevice, strlen (mi.szDevice));
+       attributes = Fcons (Fcons (Qname, name), attributes);
+ 
+       hdc = CreateDCA ("DISPLAY", mi.szDevice, NULL, NULL);
+       width_mm = GetDeviceCaps (hdc, HORZSIZE);
+       height_mm = GetDeviceCaps (hdc, VERTSIZE);
+       DeleteDC (hdc);
+       attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 			  attributes);
+ 
+       workarea = list4i (mi.rcWork.left, mi.rcWork.top,
+ 			 mi.rcWork.right - mi.rcWork.left,
+ 			 mi.rcWork.bottom - mi.rcWork.top);
+       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+       geometry = list4i (mi.rcMonitor.left, mi.rcMonitor.top,
+ 			 mi.rcMonitor.right - mi.rcMonitor.left,
+ 			 mi.rcMonitor.bottom - mi.rcMonitor.top);
+       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+       if (mi.dwFlags & MONITORINFOF_PRIMARY)
+ 	primary_monitor_attributes = attributes;
+       else
+ 	attributes_list = Fcons (attributes, attributes_list);
+     }
+ 
+   if (!NILP (primary_monitor_attributes))
+     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+ 
+   xfree (monitors);
+ 
+   return attributes_list;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list_fallback (void)
+ {
+   Lisp_Object geometry, workarea, frames, attributes = Qnil;
+   HDC hdc;
+   double mm_per_pixel;
+   int pixel_width, pixel_height, width_mm, height_mm;
+   RECT workarea_rect;
+ 
+   /* Fallback: treat (possibly) multiple physical monitors as if they
+      formed a single monitor as a whole.  This should provide a
+      consistent result at least on single monitor environments.  */
+   attributes = Fcons (Fcons (Qname, build_string ("combined screen"),
+ 			     attributes));
+ 
+   frames = Qnil;
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	frames = Fcons (frame, frames);
+     }
+   attributes = Fcons (Fcons (Qframes, frames), attributes);
+ 
+   pixel_width = x_display_pixel_width (dpyinfo);
+   pixel_height = x_display_pixel_height (dpyinfo);
+ 
+   hdc = GetDC (NULL);
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
+ 		  / GetDeviceCaps (hdc, HORZRES));
+   width_mm = pixel_width * mm_per_pixel + 0.5;
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
+ 		  / GetDeviceCaps (hdc, VERTRES));
+   height_mm = pixel_height * mm_per_pixel + 0.5;
+   ReleaseDC (NULL, hdc);
+   attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 		      attributes);
+ 
+   /* GetSystemMetrics below may return 0 for Windows 95 or NT 4.0, but
+      we don't care.  */
+   geometry = list4i (GetSystemMetrics (SM_XVIRTUALSCREEN),
+ 		     GetSystemMetrics (SM_YVIRTUALSCREEN),
+ 		     pixel_width, pixel_height);
+   if (SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0))
+     workarea = list4i (workarea_rect.left, workarea_rect.top,
+ 		       workarea_rect.right - workarea_rect.left,
+ 		       workarea_rect.bottom - workarea_rect.top);
+   else
+     workarea = geometry;
+   attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+   attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+   return list1 (attributes);
+ }
+ 
+ DEFUN ("w32-display-monitor-attributes-list", Fw32_display_monitor_attributes_list,
+        Sw32_display_monitor_attributes_list,
+        0, 1, 0,
+        doc: /* Return a list of physical monitor attributes on the W32 display DISPLAY.
+ 
+ The optional argument DISPLAY specifies which display to ask about.
+ DISPLAY should be either a frame or a display name (a string).
+ If omitted or nil, that stands for the selected frame's display.
+ 
+ Internal use only, use `display-monitor-attributes-list' instead.  */)
+   (Lisp_Object display)
+ {
+   struct w32_display_info *dpyinfo = check_x_display_info (display);
+   Lisp_Object attributes_list;
+ 
+   block_input ();
+   attributes_list = w32_display_monitor_attributes_list ();
+   if (NILP (attributes_list))
+     attributes_list = w32_display_monitor_attributes_list_fallback ();
+   unblock_input ();
+ 
+   return attributes_list;
+ }
+ 
  DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
         doc: /* Set the sound generated when the bell is rung.
  SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
***************
*** 7339,7344 ****
--- 7565,7574 ----
    DEFSYM (Qcontrol, "control");
    DEFSYM (Qshift, "shift");
    DEFSYM (Qfont_param, "font-parameter");
+   DEFSYM (Qgeometry, "geometry");
+   DEFSYM (Qworkarea, "workarea");
+   DEFSYM (Qmm_size, "mm-size");
+   DEFSYM (Qframes, "frames");
    /* This is the end of symbol initialization.  */
  
  
***************
*** 7617,7622 ****
--- 7847,7853 ----
    defsubr (&Sx_display_visual_class);
    defsubr (&Sx_display_backing_store);
    defsubr (&Sx_display_save_under);
+   defsubr (&Sw32_display_monitor_attributes_list);
    defsubr (&Sx_create_frame);
    defsubr (&Sx_open_connection);
    defsubr (&Sx_close_connection);
***************
*** 7689,7694 ****
--- 7920,7927 ----
      GetProcAddress (user32_lib, "GetMonitorInfoA");
    monitor_from_window_fn = (MonitorFromWindow_Proc)
      GetProcAddress (user32_lib, "MonitorFromWindow");
+   enum_display_monitors_fn = (EnumDisplayMonitors_Proc)
+     GetProcAddress (user32_lib, "EnumDisplayMonitors");
  
    {
      HMODULE imm32_lib = GetModuleHandle ("imm32.dll");

=== modified file 'src/w32term.c'
*** src/w32term.c	2013-04-14 00:58:45 +0000
--- src/w32term.c	2013-04-28 07:04:08 +0000
***************
*** 143,148 ****
--- 143,157 ----
  #define WS_EX_LAYERED 0x80000
  #endif
  
+ /* SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not defined on 95 and
+    NT4.  */
+ #ifndef SM_CXVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 78
+ #endif
+ #ifndef SM_CYVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 79
+ #endif
+ 
  /* This is a frame waiting to be autoraised, within w32_read_socket.  */
  struct frame *pending_autoraise_frame;
  
***************
*** 516,534 ****
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, VERTRES);
!   ReleaseDC (NULL, dc);
!   return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, HORZRES);
!   ReleaseDC (NULL, dc);
!   return pixels;
  }
  
  \f
--- 525,541 ----
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   return (GetSystemMetrics (SM_CYVIRTUALSCREEN)
! 	  /* Fallback for Windows 95 or NT 4.0.  */
! 	  || GetSystemMetrics (SM_CYSCREEN));
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   return (GetSystemMetrics (SM_CXVIRTUALSCREEN)
! 	  /* Fallback for Windows 95 or NT 4.0.  */
! 	  || GetSystemMetrics (SM_CXSCREEN));
  }
  
  \f




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

* Re: x-display-pixel-width/height inconsistency
  2013-05-08 10:46                                         ` YAMAMOTO Mitsuharu
@ 2013-05-08 11:24                                           ` YAMAMOTO Mitsuharu
  2013-05-08 17:41                                           ` Eli Zaretskii
  1 sibling, 0 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-08 11:24 UTC (permalink / raw)
  To: emacs-devel

>>>>> On Wed, 08 May 2013 19:46:51 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

> I also tried implementing a W32 version of multi-monitor support,
> but I can't test it (I didn't even compile, actually).  Please test
> it.

> + static Lisp_Object
> + w32_display_monitor_attributes_list (void)
> + {
> +   Lisp_Object attributes_list = Qnil, primary_monitor_attributes = Qnil;
> +   Lisp_Object monitor_list, monitor_frames, rest, frame;

Sorry the above line should be:

+   Lisp_Object monitor_list = Qnil, monitor_frames, rest, frame;

(initialization for monitor_list was missing.)

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-08 10:46                                         ` YAMAMOTO Mitsuharu
  2013-05-08 11:24                                           ` YAMAMOTO Mitsuharu
@ 2013-05-08 17:41                                           ` Eli Zaretskii
  2013-05-09  0:09                                             ` YAMAMOTO Mitsuharu
  1 sibling, 1 reply; 97+ messages in thread
From: Eli Zaretskii @ 2013-05-08 17:41 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Wed, 08 May 2013 19:46:51 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> 
> I also tried implementing a W32 version of multi-monitor support, but
> I can't test it (I didn't even compile, actually).  Please test it.

You need more changes to get this to compile, see the patches below
that should be applied on top of what you sent.

After that, the code seems to work on my single-monitor system.  (I
don't have access to any multi-monitor machines.)

Thanks.

P.S.  Is it possible to use something more elegant to pass a parameter
to w32_monitor_enum?  The way you did it, by casting a Lisp_Object to
a LPARAM, will not work when the width of a Lisp_Object is different
from the width of a pointer.  And even when it does work, it feels
kludgey.

P.P.S.  Would you mind to also add the necessary documentation changes,
like NEWS and additions to the ELisp manual?  TIA.


--- src/w32fns.c~0	2013-05-08 20:19:43.313375000 +0300
+++ src/w32fns.c	2013-05-08 20:31:52.704000000 +0300
@@ -4909,7 +4909,8 @@ w32_display_monitor_attributes_list (voi
 	&& monitor_from_window_fn))
     return Qnil;
 
-  if (!enum_display_monitors_fn (NULL, NULL, w32_monitor_enum, &monitor_list)
+  if (!enum_display_monitors_fn (NULL, NULL, w32_monitor_enum,
+				 (LPARAM)&monitor_list)
       || NILP (monitor_list))
     return Qnil;
 
@@ -4929,8 +4930,7 @@ w32_display_monitor_attributes_list (voi
     {
       struct frame *f = XFRAME (frame);
 
-      if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
-	  && !EQ (frame, tip_frame))
+      if (FRAME_W32_P (f) && !EQ (frame, tip_frame))
 	{
 	  HMONITOR monitor =
 	    monitor_from_window_fn (FRAME_W32_WINDOW (f),
@@ -4994,29 +4994,29 @@ w32_display_monitor_attributes_list (voi
 static Lisp_Object
 w32_display_monitor_attributes_list_fallback (void)
 {
-  Lisp_Object geometry, workarea, frames, attributes = Qnil;
+  Lisp_Object geometry, workarea, frames, rest, frame, attributes = Qnil;
   HDC hdc;
   double mm_per_pixel;
   int pixel_width, pixel_height, width_mm, height_mm;
   RECT workarea_rect;
+  struct w32_display_info *dpyinfo;
+  struct frame *f = XFRAME (frame);
 
   /* Fallback: treat (possibly) multiple physical monitors as if they
      formed a single monitor as a whole.  This should provide a
      consistent result at least on single monitor environments.  */
-  attributes = Fcons (Fcons (Qname, build_string ("combined screen"),
-			     attributes));
+  attributes = Fcons (Fcons (Qname, build_string ("combined screen")),
+			     attributes);
 
   frames = Qnil;
   FOR_EACH_FRAME (rest, frame)
     {
-      struct frame *f = XFRAME (frame);
-
-      if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
-	  && !EQ (frame, tip_frame))
+      if (FRAME_W32_P (f) && !EQ (frame, tip_frame))
 	frames = Fcons (frame, frames);
     }
   attributes = Fcons (Fcons (Qframes, frames), attributes);
 
+  dpyinfo = FRAME_W32_DISPLAY_INFO (f);
   pixel_width = x_display_pixel_width (dpyinfo);
   pixel_height = x_display_pixel_height (dpyinfo);
 



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-08 17:41                                           ` Eli Zaretskii
@ 2013-05-09  0:09                                             ` YAMAMOTO Mitsuharu
  2013-05-09  1:52                                               ` Glenn Morris
                                                                 ` (3 more replies)
  0 siblings, 4 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-09  0:09 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Wed, 08 May 2013 20:41:39 +0300, Eli Zaretskii <eliz@gnu.org> said:

>> I also tried implementing a W32 version of multi-monitor support,
>> but I can't test it (I didn't even compile, actually).  Please test
>> it.

> You need more changes to get this to compile, see the patches below
> that should be applied on top of what you sent.

> After that, the code seems to work on my single-monitor system.  (I
> don't have access to any multi-monitor machines.)

> Thanks.

Thanks for testing.  I updated the w32fns.c part below.

> P.S.  Is it possible to use something more elegant to pass a
> parameter to w32_monitor_enum?  The way you did it, by casting a
> Lisp_Object to a LPARAM, will not work when the width of a
> Lisp_Object is different from the width of a pointer.  And even when
> it does work, it feels kludgey.

No.  What is casted to an LPARAM is not a Lisp_Object value but a
*pointer to* a Lisp_Object variable.  That is a standard way of
passing context information to a callback, and I suppose such
callbacks are usually designed so they can get a pointer-sized context
as an argument.

> P.P.S.  Would you mind to also add the necessary documentation
> changes, like NEWS and additions to the ELisp manual?  TIA.

I'm planning to add an NEWS entry saying that (x-)display-pixel-width
and (x-)display-pixel-height functions now behave consistently among
the platforms, once the change for the remaining platform (i.e., NS)
is done.  (Is anyone working on implementing
ns-display-monitor-attributes-list ?).

I don't know how ELisp manual is usually updated.  Is it supposed to
be done by the same person who designed/implemented the new functions?

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'src/w32fns.c'
*** src/w32fns.c	2013-05-04 10:19:13 +0000
--- src/w32fns.c	2013-05-08 23:54:04 +0000
***************
*** 106,111 ****
--- 106,112 ----
  Lisp_Object Qctrl;
  Lisp_Object Qcontrol;
  Lisp_Object Qshift;
+ static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes;
  
  
  /* Prefix for system colors.  */
***************
*** 131,136 ****
--- 132,146 ----
  #ifndef MONITOR_DEFAULT_TO_NEAREST
  #define MONITOR_DEFAULT_TO_NEAREST 2
  #endif
+ #ifndef MONITORINFOF_PRIMARY
+ #define MONITORINFOF_PRIMARY 1
+ #endif
+ #ifndef SM_XVIRTUALSCREEN
+ #define SM_XVIRTUALSCREEN 76
+ #endif
+ #ifndef SM_YVIRTUALSCREEN
+ #define SM_YVIRTUALSCREEN 77
+ #endif
  /* MinGW headers define MONITORINFO unconditionally, but MSVC ones don't.
     To avoid a compile error on one or the other, redefine with a new name.  */
  struct MONITOR_INFO
***************
*** 141,146 ****
--- 151,168 ----
      DWORD   dwFlags;
  };
  
+ #ifndef CCHDEVICENAME
+ #define CCHDEVICENAME 32
+ #endif
+ struct MONITOR_INFO_EX
+ {
+     DWORD   cbSize;
+     RECT    rcMonitor;
+     RECT    rcWork;
+     DWORD   dwFlags;
+     char    szDevice[CCHDEVICENAME];
+ };
+ 
  /* Reportedly, MSVC does not have this in its headers.  */
  #if defined (_MSC_VER) && _WIN32_WINNT < 0x0500
  DECLARE_HANDLE(HMONITOR);
***************
*** 159,164 ****
--- 181,190 ----
    (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
  typedef HMONITOR (WINAPI * MonitorFromWindow_Proc)
    (IN HWND hwnd, IN DWORD dwFlags);
+ typedef BOOL CALLBACK (* MonitorEnum_Proc)
+   (IN HMONITOR monitor, IN HDC hdc, IN RECT *rcMonitor, IN LPARAM dwData);
+ typedef BOOL (WINAPI * EnumDisplayMonitors_Proc)
+   (IN HDC hdc, IN RECT *rcClip, IN MonitorEnum_Proc fnEnum, IN LPARAM dwData);
  
  TrackMouseEvent_Proc track_mouse_event_fn = NULL;
  ImmGetCompositionString_Proc get_composition_string_fn = NULL;
***************
*** 168,173 ****
--- 194,200 ----
  MonitorFromPoint_Proc monitor_from_point_fn = NULL;
  GetMonitorInfo_Proc get_monitor_info_fn = NULL;
  MonitorFromWindow_Proc monitor_from_window_fn = NULL;
+ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
  
  #ifdef NTGUI_UNICODE
  #define unicode_append_menu AppendMenuW
***************
*** 4656,4662 ****
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4683,4693 ----
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel width for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4669,4675 ****
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4700,4710 ----
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel height for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4761,4801 ****
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   int cap;
  
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, VERTSIZE);
! 
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
- 
    HDC hdc;
!   int cap;
! 
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, HORZSIZE);
  
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
--- 4796,4841 ----
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the height in millimeters for
! all physical monitors associated with DISPLAY.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
! 		  / GetDeviceCaps (hdc, VERTRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_height (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the width in millimeters for
! all physical monitors associated with TERMINAL.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
! 		  / GetDeviceCaps (hdc, HORZRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_width (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
***************
*** 4847,4852 ****
--- 4887,5080 ----
    return Qnil;
  }
  
+ static BOOL CALLBACK
+ w32_monitor_enum (HMONITOR monitor, HDC hdc, RECT *rcMonitor, LPARAM dwData)
+ {
+   Lisp_Object *monitor_list = (Lisp_Object *) dwData;
+ 
+   *monitor_list = Fcons (make_save_pointer (monitor), *monitor_list);
+ 
+   return TRUE;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list (struct w32_display_info *dpyinfo)
+ {
+   Lisp_Object attributes_list = Qnil, primary_monitor_attributes = Qnil;
+   Lisp_Object monitor_list = Qnil, monitor_frames, rest, frame;
+   int i, n_monitors;
+   HMONITOR *monitors;
+ 
+   if (!(enum_display_monitors_fn && get_monitor_info_fn
+ 	&& monitor_from_window_fn))
+     return Qnil;
+ 
+   if (!enum_display_monitors_fn (NULL, NULL, w32_monitor_enum,
+ 				 (LPARAM) &monitor_list)
+       || NILP (monitor_list))
+     return Qnil;
+ 
+   n_monitors = 0;
+   for (rest = monitor_list; CONSP (rest); rest = XCDR (rest))
+     n_monitors++;
+ 
+   monitors = xmalloc (n_monitors * sizeof (*monitors));
+   for (i = 0; i < n_monitors; i++)
+     {
+       monitors[i] = XSAVE_POINTER (XCAR (monitor_list), 0);
+       monitor_list = XCDR (monitor_list);
+     }
+ 
+   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	{
+ 	  HMONITOR monitor =
+ 	    monitor_from_window_fn (FRAME_W32_WINDOW (f),
+ 				    MONITOR_DEFAULT_TO_NEAREST);
+ 
+ 	  for (i = 0; i < n_monitors; i++)
+ 	    if (monitors[i] == monitor)
+ 	      break;
+ 
+ 	  if (i < n_monitors)
+ 	    ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+ 	}
+     }
+ 
+   for (i = 0; i < n_monitors; i++)
+     {
+       Lisp_Object geometry, workarea, name, attributes = Qnil;
+       HDC hdc;
+       int width_mm, height_mm;
+       struct MONITOR_INFO_EX mi;
+ 
+       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+ 			  attributes);
+ 
+       mi.cbSize = sizeof (mi);
+       get_monitor_info_fn (monitors[i], (struct MONITOR_INFO *) &mi);
+ 
+       name = make_unibyte_string (mi.szDevice, strlen (mi.szDevice));
+       attributes = Fcons (Fcons (Qname, name), attributes);
+ 
+       hdc = CreateDCA ("DISPLAY", mi.szDevice, NULL, NULL);
+       width_mm = GetDeviceCaps (hdc, HORZSIZE);
+       height_mm = GetDeviceCaps (hdc, VERTSIZE);
+       DeleteDC (hdc);
+       attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 			  attributes);
+ 
+       workarea = list4i (mi.rcWork.left, mi.rcWork.top,
+ 			 mi.rcWork.right - mi.rcWork.left,
+ 			 mi.rcWork.bottom - mi.rcWork.top);
+       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+       geometry = list4i (mi.rcMonitor.left, mi.rcMonitor.top,
+ 			 mi.rcMonitor.right - mi.rcMonitor.left,
+ 			 mi.rcMonitor.bottom - mi.rcMonitor.top);
+       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+       if (mi.dwFlags & MONITORINFOF_PRIMARY)
+ 	primary_monitor_attributes = attributes;
+       else
+ 	attributes_list = Fcons (attributes, attributes_list);
+     }
+ 
+   if (!NILP (primary_monitor_attributes))
+     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+ 
+   xfree (monitors);
+ 
+   return attributes_list;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list_fallback (struct w32_display_info *dpyinfo)
+ {
+   Lisp_Object geometry, workarea, frames, rest, frame, attributes = Qnil;
+   HDC hdc;
+   double mm_per_pixel;
+   int pixel_width, pixel_height, width_mm, height_mm;
+   RECT workarea_rect;
+ 
+   /* Fallback: treat (possibly) multiple physical monitors as if they
+      formed a single monitor as a whole.  This should provide a
+      consistent result at least on single monitor environments.  */
+   attributes = Fcons (Fcons (Qname, build_string ("combined screen")),
+ 		      attributes);
+ 
+   frames = Qnil;
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
+ 	  && !EQ (frame, tip_frame))
+ 	frames = Fcons (frame, frames);
+     }
+   attributes = Fcons (Fcons (Qframes, frames), attributes);
+ 
+   pixel_width = x_display_pixel_width (dpyinfo);
+   pixel_height = x_display_pixel_height (dpyinfo);
+ 
+   hdc = GetDC (NULL);
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
+ 		  / GetDeviceCaps (hdc, HORZRES));
+   width_mm = pixel_width * mm_per_pixel + 0.5;
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
+ 		  / GetDeviceCaps (hdc, VERTRES));
+   height_mm = pixel_height * mm_per_pixel + 0.5;
+   ReleaseDC (NULL, hdc);
+   attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 		      attributes);
+ 
+   /* GetSystemMetrics below may return 0 for Windows 95 or NT 4.0, but
+      we don't care.  */
+   geometry = list4i (GetSystemMetrics (SM_XVIRTUALSCREEN),
+ 		     GetSystemMetrics (SM_YVIRTUALSCREEN),
+ 		     pixel_width, pixel_height);
+   if (SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0))
+     workarea = list4i (workarea_rect.left, workarea_rect.top,
+ 		       workarea_rect.right - workarea_rect.left,
+ 		       workarea_rect.bottom - workarea_rect.top);
+   else
+     workarea = geometry;
+   attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+   attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+   return list1 (attributes);
+ }
+ 
+ DEFUN ("w32-display-monitor-attributes-list", Fw32_display_monitor_attributes_list,
+        Sw32_display_monitor_attributes_list,
+        0, 1, 0,
+        doc: /* Return a list of physical monitor attributes on the W32 display DISPLAY.
+ 
+ The optional argument DISPLAY specifies which display to ask about.
+ DISPLAY should be either a frame or a display name (a string).
+ If omitted or nil, that stands for the selected frame's display.
+ 
+ Internal use only, use `display-monitor-attributes-list' instead.  */)
+   (Lisp_Object display)
+ {
+   struct w32_display_info *dpyinfo = check_x_display_info (display);
+   Lisp_Object attributes_list;
+ 
+   block_input ();
+   attributes_list = w32_display_monitor_attributes_list (dpyinfo);
+   if (NILP (attributes_list))
+     attributes_list = w32_display_monitor_attributes_list_fallback (dpyinfo);
+   unblock_input ();
+ 
+   return attributes_list;
+ }
+ 
  DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
         doc: /* Set the sound generated when the bell is rung.
  SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
***************
*** 7339,7344 ****
--- 7567,7576 ----
    DEFSYM (Qcontrol, "control");
    DEFSYM (Qshift, "shift");
    DEFSYM (Qfont_param, "font-parameter");
+   DEFSYM (Qgeometry, "geometry");
+   DEFSYM (Qworkarea, "workarea");
+   DEFSYM (Qmm_size, "mm-size");
+   DEFSYM (Qframes, "frames");
    /* This is the end of symbol initialization.  */
  
  
***************
*** 7617,7622 ****
--- 7849,7855 ----
    defsubr (&Sx_display_visual_class);
    defsubr (&Sx_display_backing_store);
    defsubr (&Sx_display_save_under);
+   defsubr (&Sw32_display_monitor_attributes_list);
    defsubr (&Sx_create_frame);
    defsubr (&Sx_open_connection);
    defsubr (&Sx_close_connection);
***************
*** 7689,7694 ****
--- 7922,7929 ----
      GetProcAddress (user32_lib, "GetMonitorInfoA");
    monitor_from_window_fn = (MonitorFromWindow_Proc)
      GetProcAddress (user32_lib, "MonitorFromWindow");
+   enum_display_monitors_fn = (EnumDisplayMonitors_Proc)
+     GetProcAddress (user32_lib, "EnumDisplayMonitors");
  
    {
      HMODULE imm32_lib = GetModuleHandle ("imm32.dll");




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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  0:09                                             ` YAMAMOTO Mitsuharu
@ 2013-05-09  1:52                                               ` Glenn Morris
  2013-05-09  3:19                                                 ` YAMAMOTO Mitsuharu
  2013-05-09  2:53                                               ` Eli Zaretskii
                                                                 ` (2 subsequent siblings)
  3 siblings, 1 reply; 97+ messages in thread
From: Glenn Morris @ 2013-05-09  1:52 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Eli Zaretskii, emacs-devel

YAMAMOTO Mitsuharu wrote:

> I don't know how ELisp manual is usually updated.  Is it supposed to
> be done by the same person who designed/implemented the new functions?

Hah! :)

It is _usually_ updated by a few poor souls with little-to-no familiarity
with the code in question, who have to struggle to figure it out.

It is _supposed_ to be updated by the people who wrote the code,
(since they know it best), who should feel free to say (if necessary)
"I'm not good at documentation, please help me polish this."

Yours only-semi-jokingly...



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  0:09                                             ` YAMAMOTO Mitsuharu
  2013-05-09  1:52                                               ` Glenn Morris
@ 2013-05-09  2:53                                               ` Eli Zaretskii
  2013-05-09  8:14                                               ` Jan Djärv
  2013-05-09 20:03                                               ` Eli Zaretskii
  3 siblings, 0 replies; 97+ messages in thread
From: Eli Zaretskii @ 2013-05-09  2:53 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Thu, 09 May 2013 09:09:33 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> I don't know how ELisp manual is usually updated.  Is it supposed to
> be done by the same person who designed/implemented the new functions?

This is the best alternative, yes.  Otherwise, this is left for the
pretest, which prolongs it and also increases the probability that a
function will be left undocumented.



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  1:52                                               ` Glenn Morris
@ 2013-05-09  3:19                                                 ` YAMAMOTO Mitsuharu
  2013-05-09  6:27                                                   ` Glenn Morris
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-09  3:19 UTC (permalink / raw)
  To: Glenn Morris; +Cc: Eli Zaretskii, emacs-devel

>>>>> On Wed, 08 May 2013 21:52:56 -0400, Glenn Morris <rgm@gnu.org> said:

>> I don't know how ELisp manual is usually updated.  Is it supposed
>> to be done by the same person who designed/implemented the new
>> functions?

> Hah! :)

> It is _usually_ updated by a few poor souls with little-to-no
> familiarity with the code in question, who have to struggle to
> figure it out.

> It is _supposed_ to be updated by the people who wrote the code,
> (since they know it best), who should feel free to say (if
> necessary) "I'm not good at documentation, please help me polish
> this."

> Yours only-semi-jokingly...

What actually confused me was the following note in etc/NEWS:

  Temporary note:
  +++ indicates that the appropriate manual has already been updated.
  --- means no change in the manuals is called for.
  When you add a new item, please add it without either +++ or ---
  so we will look at it and add it to the manual.

I thought the judgement whether a new feature/function needs to be
documented in the maunal was done by a third person at a later time
(in the pretest stage, for example).

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  3:19                                                 ` YAMAMOTO Mitsuharu
@ 2013-05-09  6:27                                                   ` Glenn Morris
  0 siblings, 0 replies; 97+ messages in thread
From: Glenn Morris @ 2013-05-09  6:27 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Eli Zaretskii, emacs-devel

YAMAMOTO Mitsuharu wrote:

>   Temporary note:
>   +++ indicates that the appropriate manual has already been updated.
>   --- means no change in the manuals is called for.
>   When you add a new item, please add it without either +++ or ---
>   so we will look at it and add it to the manual.
>
> I thought the judgement whether a new feature/function needs to be
> documented in the maunal was done by a third person at a later time
> (in the pretest stage, for example).

You are encouraged to review your own changes before then.
The possibilities are:

1) If you are absolutely sure it does not need any documentation, add ---.

2) If you know it needs documentation, try to write some.
If you are absolutely positive that the documentation you have written
is correct and adequate, add +++.

3) If you really don't know whether something needs documenting or not,
either do nothing, or ask.



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  0:09                                             ` YAMAMOTO Mitsuharu
  2013-05-09  1:52                                               ` Glenn Morris
  2013-05-09  2:53                                               ` Eli Zaretskii
@ 2013-05-09  8:14                                               ` Jan Djärv
  2013-05-09  8:43                                                 ` YAMAMOTO Mitsuharu
  2013-05-09 20:03                                               ` Eli Zaretskii
  3 siblings, 1 reply; 97+ messages in thread
From: Jan Djärv @ 2013-05-09  8:14 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Eli Zaretskii, emacs-devel

Hello.

9 maj 2013 kl. 02:09 skrev YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>:

> 
> I'm planning to add an NEWS entry saying that (x-)display-pixel-width
> and (x-)display-pixel-height functions now behave consistently among
> the platforms, once the change for the remaining platform (i.e., NS)
> is done.  (Is anyone working on implementing
> ns-display-monitor-attributes-list ?).

I'm working on it.
But it seems to me that having 4 (or more) implementations of how to construct the attributes_list is not optimal.  Can we make a general function for this that the ports can call?  Somthing like XRandr, Xinerama and fallback shares in xfns.c? 

	Jan D.




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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  8:14                                               ` Jan Djärv
@ 2013-05-09  8:43                                                 ` YAMAMOTO Mitsuharu
  2013-05-09 15:18                                                   ` Jan Djärv
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-09  8:43 UTC (permalink / raw)
  To: Jan Djärv; +Cc: Eli Zaretskii, emacs-devel

>>>>> On Thu, 9 May 2013 10:14:59 +0200, Jan Djärv <jan.h.d@swipnet.se> said:

>> I'm planning to add an NEWS entry saying that
>> (x-)display-pixel-width and (x-)display-pixel-height functions now
>> behave consistently among the platforms, once the change for the
>> remaining platform (i.e., NS) is done.  (Is anyone working on
>> implementing ns-display-monitor-attributes-list ?).

> I'm working on it.  But it seems to me that having 4 (or more)
> implementations of how to construct the attributes_list is not
> optimal.  Can we make a general function for this that the ports can
> call?  Somthing like XRandr, Xinerama and fallback shares in xfns.c?

Yes.  Perhaps fallback of mm_size by approximation, which is found in
Xinerama and GDK cases, can also be consolidated.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  8:43                                                 ` YAMAMOTO Mitsuharu
@ 2013-05-09 15:18                                                   ` Jan Djärv
  0 siblings, 0 replies; 97+ messages in thread
From: Jan Djärv @ 2013-05-09 15:18 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Eli Zaretskii, emacs-devel

Hello.

I checked in an NS version.  I will do the consolidation later.

	Jan D.

9 maj 2013 kl. 10:43 skrev YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>:

>>>>>> On Thu, 9 May 2013 10:14:59 +0200, Jan Djärv <jan.h.d@swipnet.se> said:
> 
>>> I'm planning to add an NEWS entry saying that
>>> (x-)display-pixel-width and (x-)display-pixel-height functions now
>>> behave consistently among the platforms, once the change for the
>>> remaining platform (i.e., NS) is done.  (Is anyone working on
>>> implementing ns-display-monitor-attributes-list ?).
> 
>> I'm working on it.  But it seems to me that having 4 (or more)
>> implementations of how to construct the attributes_list is not
>> optimal.  Can we make a general function for this that the ports can
>> call?  Somthing like XRandr, Xinerama and fallback shares in xfns.c?
> 
> Yes.  Perhaps fallback of mm_size by approximation, which is found in
> Xinerama and GDK cases, can also be consolidated.
> 
> 				     YAMAMOTO Mitsuharu
> 				mituharu@math.s.chiba-u.ac.jp




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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09  0:09                                             ` YAMAMOTO Mitsuharu
                                                                 ` (2 preceding siblings ...)
  2013-05-09  8:14                                               ` Jan Djärv
@ 2013-05-09 20:03                                               ` Eli Zaretskii
  2013-05-09 21:28                                                 ` Stefan Monnier
  2013-05-10  6:00                                                 ` YAMAMOTO Mitsuharu
  3 siblings, 2 replies; 97+ messages in thread
From: Eli Zaretskii @ 2013-05-09 20:03 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Thu, 09 May 2013 09:09:33 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> Thanks for testing.  I updated the w32fns.c part below.

I have a couple more comments.

> + static BOOL CALLBACK
> + w32_monitor_enum (HMONITOR monitor, HDC hdc, RECT *rcMonitor, LPARAM dwData)
> + {
> +   Lisp_Object *monitor_list = (Lisp_Object *) dwData;
> + 
> +   *monitor_list = Fcons (make_save_pointer (monitor), *monitor_list);
> + 
> +   return TRUE;
> + }

It makes me nervous to have consing inside a Win32 API callback.  Are
we even sure the callback gets called in the context of our main
tread?  If not, and if consing causes GC, we could blow up the stack.

And actually, I don't see why you need the list of monitor HMONITOR
handles, you get them from MonitorFromWindow anyway.  All you need is
the count of the monitors, and then you can create the vector in
monitor_frames by simply inserting every monitor you get from
MonitorFromWindow, and leave the rest at nil.  Or am I missing
something?

So could we please get rid of the consing inside the callback, and
just count them instead?

> +       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
> + 	  && !EQ (frame, tip_frame))

The test against dpyinfo is redundant, it will always be true: there's
only one dpyinfo on Windows.  I would like to remove it, because it's
confusing.  (There's one more such test in another place in the
patch.)

> +       name = make_unibyte_string (mi.szDevice, strlen (mi.szDevice));

Why make_unibyte_string?  Is szDevice documented to be an ASCII-only
string?

> +   attributes = Fcons (Fcons (Qname, build_string ("combined screen")),
> + 		      attributes);

And using build_string here with a pure ASCII string is at least
inconsistent.  (But I actually suggest to use build_string in both
cases.)

Thanks.



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09 20:03                                               ` Eli Zaretskii
@ 2013-05-09 21:28                                                 ` Stefan Monnier
  2013-05-10  6:00                                                 ` YAMAMOTO Mitsuharu
  1 sibling, 0 replies; 97+ messages in thread
From: Stefan Monnier @ 2013-05-09 21:28 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: YAMAMOTO Mitsuharu, emacs-devel

> It makes me nervous to have consing inside a Win32 API callback.  Are

The cons-allocator is not thread-safe, so Fcons should only be called
from the main thread, and not from signal handlers either.


        Stefan



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-09 20:03                                               ` Eli Zaretskii
  2013-05-09 21:28                                                 ` Stefan Monnier
@ 2013-05-10  6:00                                                 ` YAMAMOTO Mitsuharu
  2013-05-10  6:05                                                   ` YAMAMOTO Mitsuharu
                                                                     ` (2 more replies)
  1 sibling, 3 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-10  6:00 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Thu, 09 May 2013 23:03:15 +0300, Eli Zaretskii <eliz@gnu.org> said:

>> + static BOOL CALLBACK
>> + w32_monitor_enum (HMONITOR monitor, HDC hdc, RECT *rcMonitor, LPARAM dwData)
>> + {
>> +   Lisp_Object *monitor_list = (Lisp_Object *) dwData;
>> + 
>> +   *monitor_list = Fcons (make_save_pointer (monitor), *monitor_list);
>> + 
>> +   return TRUE;
>> + }

> It makes me nervous to have consing inside a Win32 API callback.  Are
> we even sure the callback gets called in the context of our main
> tread?  If not, and if consing causes GC, we could blow up the stack.

If the callback can be called from the thread/context other than the
one for EnumDisplayMonitors and that can cause memory synchronization
issue, then API documentation should clearly say so, because such kind
of problem can happen even with other data structures.

And it is not Fcons but Feval that can cause GC.

> And actually, I don't see why you need the list of monitor HMONITOR
> handles, you get them from MonitorFromWindow anyway.  All you need is
> the count of the monitors, and then you can create the vector in
> monitor_frames by simply inserting every monitor you get from
> MonitorFromWindow, and leave the rest at nil.  Or am I missing
> something?

> So could we please get rid of the consing inside the callback, and
> just count them instead?

The display-monitor-function lists all the monitors regardless of the
existence of Emacs frames in it.

>> +       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
>> + 	  && !EQ (frame, tip_frame))

> The test against dpyinfo is redundant, it will always be true: there's
> only one dpyinfo on Windows.  I would like to remove it, because it's
> confusing.  (There's one more such test in another place in the
> patch.)

I'm aware of that.  It's just for resemblance to X11 code.  I'd rather
leave it to make it easier to compare with the code for X11 if it were
for the Mac port, but I don't have a strong opinion for W32.

>> +       name = make_unibyte_string (mi.szDevice, strlen (mi.szDevice));

> Why make_unibyte_string?  Is szDevice documented to be an ASCII-only
> string?

make_unibyte_string does not assume that the passed bytes are only of
ASCII characters.  I made it on the safe side in case the contents of
szDevice member accidentally matches with Emacs internal encoding and
misinterpreted.

Of course, you can decode the string if its encoding is known (I'm not
sure how it is encoded because I'm not familiar with W32).  But you
should be careful because code conversions can involve GC in general
unlike Fcons.  Alternatively, as the `name' attribute is optional, you
can remove it entirely if you don't like make_unibyte_string.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  6:00                                                 ` YAMAMOTO Mitsuharu
@ 2013-05-10  6:05                                                   ` YAMAMOTO Mitsuharu
  2013-05-10  7:06                                                   ` Eli Zaretskii
  2013-05-10  7:44                                                   ` Jan Djärv
  2 siblings, 0 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-10  6:05 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Fri, 10 May 2013 15:00:33 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

>> And actually, I don't see why you need the list of monitor HMONITOR
>> handles, you get them from MonitorFromWindow anyway.  All you need is
>> the count of the monitors, and then you can create the vector in
>> monitor_frames by simply inserting every monitor you get from
>> MonitorFromWindow, and leave the rest at nil.  Or am I missing
>> something?

>> So could we please get rid of the consing inside the callback, and
>> just count them instead?

> The display-monitor-function lists all the monitors regardless of the
> existence of Emacs frames in it.

s/display-monitor-function/display-monitor-attributes-list function/

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  6:00                                                 ` YAMAMOTO Mitsuharu
  2013-05-10  6:05                                                   ` YAMAMOTO Mitsuharu
@ 2013-05-10  7:06                                                   ` Eli Zaretskii
  2013-05-10  7:47                                                     ` YAMAMOTO Mitsuharu
  2013-05-10  7:44                                                   ` Jan Djärv
  2 siblings, 1 reply; 97+ messages in thread
From: Eli Zaretskii @ 2013-05-10  7:06 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Fri, 10 May 2013 15:00:33 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> > It makes me nervous to have consing inside a Win32 API callback.  Are
> > we even sure the callback gets called in the context of our main
> > tread?  If not, and if consing causes GC, we could blow up the stack.
> 
> If the callback can be called from the thread/context other than the
> one for EnumDisplayMonitors and that can cause memory synchronization
> issue, then API documentation should clearly say so, because such kind
> of problem can happen even with other data structures.

Well, we can sue MS, but that won't help us, I think.

Seriously: while debugging Emacs on Windows, I frequently see messages
from GDB about new threads being launched, which I know for sure Emacs
didn't do directly.  I have no idea why they are started.  For
example, calling GetOpenFileName certainly starts a new thread, but
the MSDN documentation says nothing about that.  (We've had problems
with the stack size of that thread, see bug #13065.)  We define a
callback for that API, and I suspect that callback is run in the
context of that additional thread.  I don't know if the API you are
using is different in this regard, but I prefer not to risk that, if
we can avoid that risk.

> And it is not Fcons but Feval that can cause GC.

Thank you for your lecture.

> > And actually, I don't see why you need the list of monitor HMONITOR
> > handles, you get them from MonitorFromWindow anyway.  All you need is
> > the count of the monitors, and then you can create the vector in
> > monitor_frames by simply inserting every monitor you get from
> > MonitorFromWindow, and leave the rest at nil.  Or am I missing
> > something?
> 
> > So could we please get rid of the consing inside the callback, and
> > just count them instead?
> 
> The display-monitor-function lists all the monitors regardless of the
> existence of Emacs frames in it.

I know that, but you end up with just nil in the list of frames for
those monitors that don't have frames, right?  So just use the
callback to count the monitors; then you don't need to cons a list
inside the callback, you only need to increment a counter.  The cells
for the monitors that don't have frames just need to be filled with
nil.

> >> +       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
> >> + 	  && !EQ (frame, tip_frame))
> 
> > The test against dpyinfo is redundant, it will always be true: there's
> > only one dpyinfo on Windows.  I would like to remove it, because it's
> > confusing.  (There's one more such test in another place in the
> > patch.)
> 
> I'm aware of that.  It's just for resemblance to X11 code.  I'd rather
> leave it to make it easier to compare with the code for X11 if it were
> for the Mac port, but I don't have a strong opinion for W32.

The w32 display doesn't support multiple display terminals, and
probably never will.  Even if it does some day support that, I doubt
that the infrastructure for that will be similar to X.

So please remove that.

> >> +       name = make_unibyte_string (mi.szDevice, strlen (mi.szDevice));
> 
> > Why make_unibyte_string?  Is szDevice documented to be an ASCII-only
> > string?
> 
> make_unibyte_string does not assume that the passed bytes are only of
> ASCII characters.

Any other string will get users in trouble, because this will produce
a unibyte string, something Lisp programs generally don't expect to
get when the string is supposed to be human-readable text.

> Of course, you can decode the string if its encoding is known (I'm not
> sure how it is encoded because I'm not familiar with W32).

You want DECODE_SYSTEM.  It knows about the encoding of strings in the
current session.

> But you should be careful because code conversions can involve GC in
> general unlike Fcons.

Then use GCPRO (although I don't think it's needed in this case).
It's not a big deal.

> Alternatively, as the `name' attribute is optional, you can remove
> it entirely if you don't like make_unibyte_string.

I see no reason to remove it due to such a minor and easily solvable
issue.

Thanks.



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  6:00                                                 ` YAMAMOTO Mitsuharu
  2013-05-10  6:05                                                   ` YAMAMOTO Mitsuharu
  2013-05-10  7:06                                                   ` Eli Zaretskii
@ 2013-05-10  7:44                                                   ` Jan Djärv
  2 siblings, 0 replies; 97+ messages in thread
From: Jan Djärv @ 2013-05-10  7:44 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Eli Zaretskii, emacs-devel


10 maj 2013 kl. 08:00 skrev YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>:

> 
>>> +       if (FRAME_W32_P (f) && FRAME_W32_DISPLAY_INFO (f) == dpyinfo
>>> + 	  && !EQ (frame, tip_frame))
> 
>> The test against dpyinfo is redundant, it will always be true: there's
>> only one dpyinfo on Windows.  I would like to remove it, because it's
>> confusing.  (There's one more such test in another place in the
>> patch.)
> 
> I'm aware of that.  It's just for resemblance to X11 code.  I'd rather
> leave it to make it easier to compare with the code for X11 if it were
> for the Mac port, but I don't have a strong opinion for W32.

FWIW, I removed the dpyinfo test in the NS-code.

	Jan D.





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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  7:06                                                   ` Eli Zaretskii
@ 2013-05-10  7:47                                                     ` YAMAMOTO Mitsuharu
  2013-05-10  8:41                                                       ` Eli Zaretskii
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-10  7:47 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Fri, 10 May 2013 10:06:18 +0300, Eli Zaretskii <eliz@gnu.org> said:

>> > It makes me nervous to have consing inside a Win32 API callback.  Are
>> > we even sure the callback gets called in the context of our main
>> > tread?  If not, and if consing causes GC, we could blow up the stack.
>> 
>> If the callback can be called from the thread/context other than the
>> one for EnumDisplayMonitors and that can cause memory synchronization
>> issue, then API documentation should clearly say so, because such kind
>> of problem can happen even with other data structures.

> Well, we can sue MS, but that won't help us, I think.

> Seriously: while debugging Emacs on Windows, I frequently see messages
> from GDB about new threads being launched, which I know for sure Emacs
> didn't do directly.  I have no idea why they are started.  For
> example, calling GetOpenFileName certainly starts a new thread, but
> the MSDN documentation says nothing about that.  (We've had problems
> with the stack size of that thread, see bug #13065.)  We define a
> callback for that API, and I suspect that callback is run in the
> context of that additional thread.  I don't know if the API you are
> using is different in this regard, but I prefer not to risk that, if
> we can avoid that risk.

Even if the callback is called in another thread (though I don't think
there is a particular reason to do so), that is indistinguishable for
Fcons from the call in the same thread if memory is properly
synchronized before the call among different processors/cores.  If not
properly synchronized, use of other data structures such as a simple
linked list does not solve the problem either (you can't even count
the number of monitors without explicit synchronization by mutex).

>> > And actually, I don't see why you need the list of monitor HMONITOR
>> > handles, you get them from MonitorFromWindow anyway.  All you need is
>> > the count of the monitors, and then you can create the vector in
>> > monitor_frames by simply inserting every monitor you get from
>> > MonitorFromWindow, and leave the rest at nil.  Or am I missing
>> > something?
>> 
>> > So could we please get rid of the consing inside the callback, and
>> > just count them instead?
>> 
>> The display-monitor-function lists all the monitors regardless of the
>> existence of Emacs frames in it.

> I know that, but you end up with just nil in the list of frames for
> those monitors that don't have frames, right?  So just use the
> callback to count the monitors; then you don't need to cons a list
> inside the callback, you only need to increment a counter.  The cells
> for the monitors that don't have frames just need to be filled with
> nil.

How do you get HMONITOR, which is necessary for GetMonitorInfo, for a
monitor in which no Emacs frames reside?

>> Of course, you can decode the string if its encoding is known (I'm not
>> sure how it is encoded because I'm not familiar with W32).

> You want DECODE_SYSTEM.  It knows about the encoding of strings in the
> current session.

Thanks for the info.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  7:47                                                     ` YAMAMOTO Mitsuharu
@ 2013-05-10  8:41                                                       ` Eli Zaretskii
  2013-05-10  8:55                                                         ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Eli Zaretskii @ 2013-05-10  8:41 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Fri, 10 May 2013 16:47:36 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> Even if the callback is called in another thread (though I don't think
> there is a particular reason to do so), that is indistinguishable for
> Fcons from the call in the same thread if memory is properly
> synchronized before the call among different processors/cores.

We don't know if this is the case, and probably never will.  (I tried
to search the net for any additional information about this API, but
came up empty-handed.)

> If not properly synchronized, use of other data structures such as a
> simple linked list does not solve the problem either (you can't even
> count the number of monitors without explicit synchronization by
> mutex).

You can count monitors with EnumDisplayMonitors if you pass to the
callback a pointer to a static int variable, which the callback will
increment.  You can then allocate an array of a suitable size and call
EnumDisplayMonitors again, this time filling the array with HMONITOR
handles, one at a time.  This makes sure we don't cons and don't
otherwise allocate memory inside a callback.



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  8:41                                                       ` Eli Zaretskii
@ 2013-05-10  8:55                                                         ` YAMAMOTO Mitsuharu
  2013-05-10  9:15                                                           ` Eli Zaretskii
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-10  8:55 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

>>>>> On Fri, 10 May 2013 11:41:38 +0300, Eli Zaretskii <eliz@gnu.org> said:

>> If not properly synchronized, use of other data structures such as
>> a simple linked list does not solve the problem either (you can't
>> even count the number of monitors without explicit synchronization
>> by mutex).

> You can count monitors with EnumDisplayMonitors if you pass to the
> callback a pointer to a static int variable, which the callback will
> increment.  You can then allocate an array of a suitable size and
> call EnumDisplayMonitors again, this time filling the array with
> HMONITOR handles, one at a time.  This makes sure we don't cons and
> don't otherwise allocate memory inside a callback.

Of course, that is another way (and GDK does similar).  But not just
counting as you described in the previous mail.  And (another) person
would say why you call EnumDisplayMonitors twice whereas one call
suffices if you use some appropriate data structure (and why you use a
pointer to a static int variable rather than that to an automatic int
variable), if I proposed such a code first.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  8:55                                                         ` YAMAMOTO Mitsuharu
@ 2013-05-10  9:15                                                           ` Eli Zaretskii
  2013-05-10  9:27                                                             ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: Eli Zaretskii @ 2013-05-10  9:15 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

> Date: Fri, 10 May 2013 17:55:28 +0900
> From: YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp>
> Cc: emacs-devel@gnu.org
> 
> And (another) person would say why you call EnumDisplayMonitors
> twice whereas one call suffices if you use some appropriate data
> structure (and why you use a pointer to a static int variable rather
> than that to an automatic int variable), if I proposed such a code
> first.

I guess we have a good answer to that now ;-)

Thanks.



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  9:15                                                           ` Eli Zaretskii
@ 2013-05-10  9:27                                                             ` YAMAMOTO Mitsuharu
  2013-05-14 10:39                                                               ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-10  9:27 UTC (permalink / raw)
  To: emacs-devel

By the way, has anyone tried the patch for W32 on a real multi-monitor
setup?  I'd like to know the results for the following expressions:

  (display-monitor-attributes-list)

  (list (display-pixel-width) (display-pixel-height))

If the output of the first result contains non-ASCII characters in the
`name' attribute, please exclude it, because the monitor name is not
decoded in the proposed patch (yet).

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-05-10  9:27                                                             ` YAMAMOTO Mitsuharu
@ 2013-05-14 10:39                                                               ` YAMAMOTO Mitsuharu
  2013-07-01  6:49                                                                 ` martin rudalics
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-05-14 10:39 UTC (permalink / raw)
  To: emacs-devel

>>>>> On Fri, 10 May 2013 18:27:15 +0900, YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> said:

> By the way, has anyone tried the patch for W32 on a real multi-monitor
> setup?  I'd like to know the results for the following expressions:

>   (display-monitor-attributes-list)

>   (list (display-pixel-width) (display-pixel-height))

There was a silly mistake in the previous patch.  Please try the
following one instead.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'lisp/frame.el'
*** lisp/frame.el	2013-05-11 02:27:28 +0000
--- lisp/frame.el	2013-05-11 03:30:27 +0000
***************
*** 1365,1371 ****
  
  (defun display-pixel-height (&optional display)
    "Return the height of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
--- 1365,1375 ----
  
  (defun display-pixel-height (&optional display)
    "Return the height of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the pixel height for all physical monitors associated
! with DISPLAY.  To get information for each physical monitor, use
! `display-monitor-attributes-list'."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
***************
*** 1377,1383 ****
  
  (defun display-pixel-width (&optional display)
    "Return the width of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
--- 1381,1391 ----
  
  (defun display-pixel-width (&optional display)
    "Return the width of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the pixel width for all physical monitors associated
! with DISPLAY.  To get information for each physical monitor, use
! `display-monitor-attributes-list'."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
***************
*** 1408,1414 ****
  (defun display-mm-height (&optional display)
    "Return the height of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cddr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
--- 1416,1426 ----
  (defun display-mm-height (&optional display)
    "Return the height of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the height in millimeters for all physical monitors
! associated with DISPLAY.  To get information for each physical
! monitor, use `display-monitor-attributes-list'."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cddr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
***************
*** 1420,1426 ****
  (defun display-mm-width (&optional display)
    "Return the width of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cadr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
--- 1432,1442 ----
  (defun display-mm-width (&optional display)
    "Return the width of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the width in millimeters for all physical monitors
! associated with DISPLAY.  To get information for each physical
! monitor, use `display-monitor-attributes-list'."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cadr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
***************
*** 1495,1500 ****
--- 1511,1518 ----
  
  (declare-function x-display-monitor-attributes-list "xfns.c"
  		  (&optional terminal))
+ (declare-function w32-display-monitor-attributes-list "w32fns.c"
+ 		  (&optional display))
  (declare-function ns-display-monitor-attributes-list "nsfns.m"
  		  (&optional terminal))
  
***************
*** 1530,1535 ****
--- 1548,1555 ----
      (cond
       ((eq frame-type 'x)
        (x-display-monitor-attributes-list display))
+      ((eq frame-type 'w32)
+       (w32-display-monitor-attributes-list display))
       ((eq frame-type 'ns)
        (ns-display-monitor-attributes-list display))
       (t

=== modified file 'src/w32fns.c'
*** src/w32fns.c	2013-05-04 10:19:13 +0000
--- src/w32fns.c	2013-05-13 09:56:30 +0000
***************
*** 106,111 ****
--- 106,112 ----
  Lisp_Object Qctrl;
  Lisp_Object Qcontrol;
  Lisp_Object Qshift;
+ static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes;
  
  
  /* Prefix for system colors.  */
***************
*** 131,136 ****
--- 132,146 ----
  #ifndef MONITOR_DEFAULT_TO_NEAREST
  #define MONITOR_DEFAULT_TO_NEAREST 2
  #endif
+ #ifndef MONITORINFOF_PRIMARY
+ #define MONITORINFOF_PRIMARY 1
+ #endif
+ #ifndef SM_XVIRTUALSCREEN
+ #define SM_XVIRTUALSCREEN 76
+ #endif
+ #ifndef SM_YVIRTUALSCREEN
+ #define SM_YVIRTUALSCREEN 77
+ #endif
  /* MinGW headers define MONITORINFO unconditionally, but MSVC ones don't.
     To avoid a compile error on one or the other, redefine with a new name.  */
  struct MONITOR_INFO
***************
*** 141,146 ****
--- 151,168 ----
      DWORD   dwFlags;
  };
  
+ #ifndef CCHDEVICENAME
+ #define CCHDEVICENAME 32
+ #endif
+ struct MONITOR_INFO_EX
+ {
+     DWORD   cbSize;
+     RECT    rcMonitor;
+     RECT    rcWork;
+     DWORD   dwFlags;
+     char    szDevice[CCHDEVICENAME];
+ };
+ 
  /* Reportedly, MSVC does not have this in its headers.  */
  #if defined (_MSC_VER) && _WIN32_WINNT < 0x0500
  DECLARE_HANDLE(HMONITOR);
***************
*** 159,164 ****
--- 181,190 ----
    (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
  typedef HMONITOR (WINAPI * MonitorFromWindow_Proc)
    (IN HWND hwnd, IN DWORD dwFlags);
+ typedef BOOL CALLBACK (* MonitorEnum_Proc)
+   (IN HMONITOR monitor, IN HDC hdc, IN RECT *rcMonitor, IN LPARAM dwData);
+ typedef BOOL (WINAPI * EnumDisplayMonitors_Proc)
+   (IN HDC hdc, IN RECT *rcClip, IN MonitorEnum_Proc fnEnum, IN LPARAM dwData);
  
  TrackMouseEvent_Proc track_mouse_event_fn = NULL;
  ImmGetCompositionString_Proc get_composition_string_fn = NULL;
***************
*** 168,173 ****
--- 194,200 ----
  MonitorFromPoint_Proc monitor_from_point_fn = NULL;
  GetMonitorInfo_Proc get_monitor_info_fn = NULL;
  MonitorFromWindow_Proc monitor_from_window_fn = NULL;
+ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
  
  #ifdef NTGUI_UNICODE
  #define unicode_append_menu AppendMenuW
***************
*** 4656,4662 ****
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4683,4693 ----
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel width for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4669,4675 ****
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4700,4710 ----
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel height for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4761,4801 ****
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   int cap;
  
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, VERTSIZE);
! 
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
- 
    HDC hdc;
!   int cap;
! 
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, HORZSIZE);
  
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
--- 4796,4841 ----
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the height in millimeters for
! all physical monitors associated with DISPLAY.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
! 		  / GetDeviceCaps (hdc, VERTRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_height (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the width in millimeters for
! all physical monitors associated with TERMINAL.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
! 		  / GetDeviceCaps (hdc, HORZRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_width (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
***************
*** 4847,4852 ****
--- 4887,5088 ----
    return Qnil;
  }
  
+ static BOOL CALLBACK
+ w32_monitor_enum (HMONITOR monitor, HDC hdc, RECT *rcMonitor, LPARAM dwData)
+ {
+   Lisp_Object *monitor_list = (Lisp_Object *) dwData;
+ 
+   *monitor_list = Fcons (make_save_pointer (monitor), *monitor_list);
+ 
+   return TRUE;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list (void)
+ {
+   Lisp_Object attributes_list = Qnil, primary_monitor_attributes = Qnil;
+   Lisp_Object monitor_list = Qnil, monitor_frames, rest, frame;
+   int i, n_monitors;
+   HMONITOR *monitors;
+   struct gcpro gcpro1, gcpro2, gcpro3;
+ 
+   if (!(enum_display_monitors_fn && get_monitor_info_fn
+ 	&& monitor_from_window_fn))
+     return Qnil;
+ 
+   if (!enum_display_monitors_fn (NULL, NULL, w32_monitor_enum,
+ 				 (LPARAM) &monitor_list)
+       || NILP (monitor_list))
+     return Qnil;
+ 
+   n_monitors = 0;
+   for (rest = monitor_list; CONSP (rest); rest = XCDR (rest))
+     n_monitors++;
+ 
+   monitors = xmalloc (n_monitors * sizeof (*monitors));
+   for (i = 0; i < n_monitors; i++)
+     {
+       monitors[i] = XSAVE_POINTER (XCAR (monitor_list), 0);
+       monitor_list = XCDR (monitor_list);
+     }
+ 
+   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && !EQ (frame, tip_frame))
+ 	{
+ 	  HMONITOR monitor =
+ 	    monitor_from_window_fn (FRAME_W32_WINDOW (f),
+ 				    MONITOR_DEFAULT_TO_NEAREST);
+ 
+ 	  for (i = 0; i < n_monitors; i++)
+ 	    if (monitors[i] == monitor)
+ 	      break;
+ 
+ 	  if (i < n_monitors)
+ 	    ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+ 	}
+     }
+ 
+   GCPRO3 (attributes_list, primary_monitor_attributes, monitor_frames);
+ 
+   for (i = 0; i < n_monitors; i++)
+     {
+       Lisp_Object geometry, workarea, name, attributes = Qnil;
+       HDC hdc;
+       int width_mm, height_mm;
+       struct MONITOR_INFO_EX mi;
+ 
+       mi.cbSize = sizeof (mi);
+       if (!get_monitor_info_fn (monitors[i], (struct MONITOR_INFO *) &mi))
+ 	continue;
+ 
+       hdc = CreateDCA ("DISPLAY", mi.szDevice, NULL, NULL);
+       if (hdc == NULL)
+ 	continue;
+       width_mm = GetDeviceCaps (hdc, HORZSIZE);
+       height_mm = GetDeviceCaps (hdc, VERTSIZE);
+       DeleteDC (hdc);
+ 
+       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+ 			  attributes);
+ 
+       name = DECODE_SYSTEM (make_unibyte_string (mi.szDevice,
+ 						 strlen (mi.szDevice)));
+       attributes = Fcons (Fcons (Qname, name), attributes);
+ 
+       attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 			  attributes);
+ 
+       workarea = list4i (mi.rcWork.left, mi.rcWork.top,
+ 			 mi.rcWork.right - mi.rcWork.left,
+ 			 mi.rcWork.bottom - mi.rcWork.top);
+       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+       geometry = list4i (mi.rcMonitor.left, mi.rcMonitor.top,
+ 			 mi.rcMonitor.right - mi.rcMonitor.left,
+ 			 mi.rcMonitor.bottom - mi.rcMonitor.top);
+       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+       if (mi.dwFlags & MONITORINFOF_PRIMARY)
+ 	primary_monitor_attributes = attributes;
+       else
+ 	attributes_list = Fcons (attributes, attributes_list);
+     }
+ 
+   if (!NILP (primary_monitor_attributes))
+     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+ 
+   UNGCPRO;
+ 
+   xfree (monitors);
+ 
+   return attributes_list;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list_fallback (struct w32_display_info *dpyinfo)
+ {
+   Lisp_Object geometry, workarea, frames, rest, frame, attributes = Qnil;
+   HDC hdc;
+   double mm_per_pixel;
+   int pixel_width, pixel_height, width_mm, height_mm;
+   RECT workarea_rect;
+ 
+   /* Fallback: treat (possibly) multiple physical monitors as if they
+      formed a single monitor as a whole.  This should provide a
+      consistent result at least on single monitor environments.  */
+   attributes = Fcons (Fcons (Qname, build_string ("combined screen")),
+ 		      attributes);
+ 
+   frames = Qnil;
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && !EQ (frame, tip_frame))
+ 	frames = Fcons (frame, frames);
+     }
+   attributes = Fcons (Fcons (Qframes, frames), attributes);
+ 
+   pixel_width = x_display_pixel_width (dpyinfo);
+   pixel_height = x_display_pixel_height (dpyinfo);
+ 
+   hdc = GetDC (NULL);
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
+ 		  / GetDeviceCaps (hdc, HORZRES));
+   width_mm = pixel_width * mm_per_pixel + 0.5;
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
+ 		  / GetDeviceCaps (hdc, VERTRES));
+   height_mm = pixel_height * mm_per_pixel + 0.5;
+   ReleaseDC (NULL, hdc);
+   attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 		      attributes);
+ 
+   /* GetSystemMetrics below may return 0 for Windows 95 or NT 4.0, but
+      we don't care.  */
+   geometry = list4i (GetSystemMetrics (SM_XVIRTUALSCREEN),
+ 		     GetSystemMetrics (SM_YVIRTUALSCREEN),
+ 		     pixel_width, pixel_height);
+   if (SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0))
+     workarea = list4i (workarea_rect.left, workarea_rect.top,
+ 		       workarea_rect.right - workarea_rect.left,
+ 		       workarea_rect.bottom - workarea_rect.top);
+   else
+     workarea = geometry;
+   attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+   attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+   return list1 (attributes);
+ }
+ 
+ DEFUN ("w32-display-monitor-attributes-list", Fw32_display_monitor_attributes_list,
+        Sw32_display_monitor_attributes_list,
+        0, 1, 0,
+        doc: /* Return a list of physical monitor attributes on the W32 display DISPLAY.
+ 
+ The optional argument DISPLAY specifies which display to ask about.
+ DISPLAY should be either a frame or a display name (a string).
+ If omitted or nil, that stands for the selected frame's display.
+ 
+ Internal use only, use `display-monitor-attributes-list' instead.  */)
+   (Lisp_Object display)
+ {
+   struct w32_display_info *dpyinfo = check_x_display_info (display);
+   Lisp_Object attributes_list;
+ 
+   block_input ();
+   attributes_list = w32_display_monitor_attributes_list ();
+   if (NILP (attributes_list))
+     attributes_list = w32_display_monitor_attributes_list_fallback (dpyinfo);
+   unblock_input ();
+ 
+   return attributes_list;
+ }
+ 
  DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
         doc: /* Set the sound generated when the bell is rung.
  SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
***************
*** 7339,7344 ****
--- 7575,7584 ----
    DEFSYM (Qcontrol, "control");
    DEFSYM (Qshift, "shift");
    DEFSYM (Qfont_param, "font-parameter");
+   DEFSYM (Qgeometry, "geometry");
+   DEFSYM (Qworkarea, "workarea");
+   DEFSYM (Qmm_size, "mm-size");
+   DEFSYM (Qframes, "frames");
    /* This is the end of symbol initialization.  */
  
  
***************
*** 7617,7622 ****
--- 7857,7863 ----
    defsubr (&Sx_display_visual_class);
    defsubr (&Sx_display_backing_store);
    defsubr (&Sx_display_save_under);
+   defsubr (&Sw32_display_monitor_attributes_list);
    defsubr (&Sx_create_frame);
    defsubr (&Sx_open_connection);
    defsubr (&Sx_close_connection);
***************
*** 7689,7694 ****
--- 7930,7937 ----
      GetProcAddress (user32_lib, "GetMonitorInfoA");
    monitor_from_window_fn = (MonitorFromWindow_Proc)
      GetProcAddress (user32_lib, "MonitorFromWindow");
+   enum_display_monitors_fn = (EnumDisplayMonitors_Proc)
+     GetProcAddress (user32_lib, "EnumDisplayMonitors");
  
    {
      HMODULE imm32_lib = GetModuleHandle ("imm32.dll");

=== modified file 'src/w32term.c'
*** src/w32term.c	2013-04-14 00:58:45 +0000
--- src/w32term.c	2013-05-14 10:32:39 +0000
***************
*** 143,148 ****
--- 143,157 ----
  #define WS_EX_LAYERED 0x80000
  #endif
  
+ /* SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not defined on 95 and
+    NT4.  */
+ #ifndef SM_CXVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 78
+ #endif
+ #ifndef SM_CYVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 79
+ #endif
+ 
  /* This is a frame waiting to be autoraised, within w32_read_socket.  */
  struct frame *pending_autoraise_frame;
  
***************
*** 516,533 ****
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, VERTRES);
!   ReleaseDC (NULL, dc);
    return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, HORZRES);
!   ReleaseDC (NULL, dc);
    return pixels;
  }
  
--- 525,548 ----
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   int pixels = GetSystemMetrics (SM_CYVIRTUALSCREEN);
! 
!   if (pixels == 0)
!     /* Fallback for Windows 95 or NT 4.0.  */
!     pixels = GetSystemMetrics (SM_CYSCREEN);
! 
    return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   int pixels = GetSystemMetrics (SM_CXVIRTUALSCREEN);
! 
!   if (pixels == 0)
!     /* Fallback for Windows 95 or NT 4.0.  */
!     pixels = GetSystemMetrics (SM_CXSCREEN);
! 
    return pixels;
  }
  




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

* Re: x-display-pixel-width/height inconsistency
  2013-05-14 10:39                                                               ` YAMAMOTO Mitsuharu
@ 2013-07-01  6:49                                                                 ` martin rudalics
  2013-07-02  1:30                                                                   ` YAMAMOTO Mitsuharu
  0 siblings, 1 reply; 97+ messages in thread
From: martin rudalics @ 2013-07-01  6:49 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: emacs-devel

 >> By the way, has anyone tried the patch for W32 on a real multi-monitor
 >> setup?  I'd like to know the results for the following expressions:
 >
 >>   (display-monitor-attributes-list)
 >
 >>   (list (display-pixel-width) (display-pixel-height))
 >
 > There was a silly mistake in the previous patch.  Please try the
 > following one instead.

Sorry for the late answer.

Unfortunately, the patch in this form doesn't apply any more on trunk.
If you have the time, please consider adapting it so we can try it.

Thanks, martin



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-01  6:49                                                                 ` martin rudalics
@ 2013-07-02  1:30                                                                   ` YAMAMOTO Mitsuharu
  2013-07-02 10:38                                                                     ` martin rudalics
  0 siblings, 1 reply; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-07-02  1:30 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel

>>>>> On Mon, 01 Jul 2013 08:49:28 +0200, martin rudalics <rudalics@gmx.at> said:

>>> By the way, has anyone tried the patch for W32 on a real
>>> multi-monitor setup?  I'd like to know the results for the
>>> following expressions:
>> 
>>> (display-monitor-attributes-list)
>> 
>>> (list (display-pixel-width) (display-pixel-height))
>> 
>> There was a silly mistake in the previous patch.  Please try the
>> following one instead.

> Sorry for the late answer.

> Unfortunately, the patch in this form doesn't apply any more on
> trunk.  If you have the time, please consider adapting it so we can
> try it.

Sure.  Please try the following patch.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp

=== modified file 'lisp/frame.el'
*** lisp/frame.el	2013-05-11 02:27:28 +0000
--- lisp/frame.el	2013-05-11 03:30:27 +0000
***************
*** 1365,1371 ****
  
  (defun display-pixel-height (&optional display)
    "Return the height of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
--- 1365,1375 ----
  
  (defun display-pixel-height (&optional display)
    "Return the height of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the pixel height for all physical monitors associated
! with DISPLAY.  To get information for each physical monitor, use
! `display-monitor-attributes-list'."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
***************
*** 1377,1383 ****
  
  (defun display-pixel-width (&optional display)
    "Return the width of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
--- 1381,1391 ----
  
  (defun display-pixel-width (&optional display)
    "Return the width of DISPLAY's screen in pixels.
! For character terminals, each character counts as a single pixel.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the pixel width for all physical monitors associated
! with DISPLAY.  To get information for each physical monitor, use
! `display-monitor-attributes-list'."
    (let ((frame-type (framep-on-display display)))
      (cond
       ((memq frame-type '(x w32 ns))
***************
*** 1408,1414 ****
  (defun display-mm-height (&optional display)
    "Return the height of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cddr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
--- 1416,1426 ----
  (defun display-mm-height (&optional display)
    "Return the height of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the height in millimeters for all physical monitors
! associated with DISPLAY.  To get information for each physical
! monitor, use `display-monitor-attributes-list'."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cddr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
***************
*** 1420,1426 ****
  (defun display-mm-width (&optional display)
    "Return the width of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cadr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
--- 1432,1442 ----
  (defun display-mm-width (&optional display)
    "Return the width of DISPLAY's screen in millimeters.
  System values can be overridden by `display-mm-dimensions-alist'.
! If the information is unavailable, value is nil.
! For graphical terminals, note that on \"multi-monitor\" setups this
! refers to the width in millimeters for all physical monitors
! associated with DISPLAY.  To get information for each physical
! monitor, use `display-monitor-attributes-list'."
    (and (memq (framep-on-display display) '(x w32 ns))
         (or (cadr (assoc (or display (frame-parameter nil 'display))
  			display-mm-dimensions-alist))
***************
*** 1495,1500 ****
--- 1511,1518 ----
  
  (declare-function x-display-monitor-attributes-list "xfns.c"
  		  (&optional terminal))
+ (declare-function w32-display-monitor-attributes-list "w32fns.c"
+ 		  (&optional display))
  (declare-function ns-display-monitor-attributes-list "nsfns.m"
  		  (&optional terminal))
  
***************
*** 1530,1535 ****
--- 1548,1555 ----
      (cond
       ((eq frame-type 'x)
        (x-display-monitor-attributes-list display))
+      ((eq frame-type 'w32)
+       (w32-display-monitor-attributes-list display))
       ((eq frame-type 'ns)
        (ns-display-monitor-attributes-list display))
       (t

=== modified file 'src/w32fns.c'
*** src/w32fns.c	2013-06-20 17:36:24 +0000
--- src/w32fns.c	2013-06-20 23:51:45 +0000
***************
*** 106,111 ****
--- 106,112 ----
  Lisp_Object Qctrl;
  Lisp_Object Qcontrol;
  Lisp_Object Qshift;
+ static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes;
  
  
  /* Prefix for system colors.  */
***************
*** 131,136 ****
--- 132,146 ----
  #ifndef MONITOR_DEFAULT_TO_NEAREST
  #define MONITOR_DEFAULT_TO_NEAREST 2
  #endif
+ #ifndef MONITORINFOF_PRIMARY
+ #define MONITORINFOF_PRIMARY 1
+ #endif
+ #ifndef SM_XVIRTUALSCREEN
+ #define SM_XVIRTUALSCREEN 76
+ #endif
+ #ifndef SM_YVIRTUALSCREEN
+ #define SM_YVIRTUALSCREEN 77
+ #endif
  /* MinGW headers define MONITORINFO unconditionally, but MSVC ones don't.
     To avoid a compile error on one or the other, redefine with a new name.  */
  struct MONITOR_INFO
***************
*** 141,146 ****
--- 151,168 ----
      DWORD   dwFlags;
  };
  
+ #ifndef CCHDEVICENAME
+ #define CCHDEVICENAME 32
+ #endif
+ struct MONITOR_INFO_EX
+ {
+     DWORD   cbSize;
+     RECT    rcMonitor;
+     RECT    rcWork;
+     DWORD   dwFlags;
+     char    szDevice[CCHDEVICENAME];
+ };
+ 
  /* Reportedly, MSVC does not have this in its headers.  */
  #if defined (_MSC_VER) && _WIN32_WINNT < 0x0500
  DECLARE_HANDLE(HMONITOR);
***************
*** 159,164 ****
--- 181,190 ----
    (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
  typedef HMONITOR (WINAPI * MonitorFromWindow_Proc)
    (IN HWND hwnd, IN DWORD dwFlags);
+ typedef BOOL CALLBACK (* MonitorEnum_Proc)
+   (IN HMONITOR monitor, IN HDC hdc, IN RECT *rcMonitor, IN LPARAM dwData);
+ typedef BOOL (WINAPI * EnumDisplayMonitors_Proc)
+   (IN HDC hdc, IN RECT *rcClip, IN MonitorEnum_Proc fnEnum, IN LPARAM dwData);
  
  TrackMouseEvent_Proc track_mouse_event_fn = NULL;
  ImmGetCompositionString_Proc get_composition_string_fn = NULL;
***************
*** 168,173 ****
--- 194,200 ----
  MonitorFromPoint_Proc monitor_from_point_fn = NULL;
  GetMonitorInfo_Proc get_monitor_info_fn = NULL;
  MonitorFromWindow_Proc monitor_from_window_fn = NULL;
+ EnumDisplayMonitors_Proc enum_display_monitors_fn = NULL;
  
  #ifdef NTGUI_UNICODE
  #define unicode_append_menu AppendMenuW
***************
*** 4674,4680 ****
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4701,4711 ----
         doc: /* Return the width in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel width for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4687,4693 ****
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
--- 4718,4728 ----
         doc: /* Return the height in pixels of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the pixel height for all
! physical monitors associated with DISPLAY.  To get information for
! each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
***************
*** 4779,4819 ****
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   int cap;
  
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, VERTSIZE);
! 
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
- 
    HDC hdc;
!   int cap;
! 
!   hdc = GetDC (dpyinfo->root_window);
  
!   cap = GetDeviceCaps (hdc, HORZSIZE);
  
!   ReleaseDC (dpyinfo->root_window, hdc);
! 
!   return make_number (cap);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
--- 4814,4859 ----
         doc: /* Return the height in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the height in millimeters for
! all physical monitors associated with DISPLAY.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
! 		  / GetDeviceCaps (hdc, VERTRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_height (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
         doc: /* Return the width in millimeters of DISPLAY.
  The optional argument DISPLAY specifies which display to ask about.
  DISPLAY should be either a frame or a display name (a string).
! If omitted or nil, that stands for the selected frame's display.
! 
! On \"multi-monitor\" setups this refers to the width in millimeters for
! all physical monitors associated with TERMINAL.  To get information
! for each physical monitor, use `display-monitor-attributes-list'.  */)
    (Lisp_Object display)
  {
    struct w32_display_info *dpyinfo = check_x_display_info (display);
    HDC hdc;
!   double mm_per_pixel;
  
!   hdc = GetDC (NULL);
!   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
! 		  / GetDeviceCaps (hdc, HORZRES));
!   ReleaseDC (NULL, hdc);
  
!   return make_number (x_display_pixel_width (dpyinfo) * mm_per_pixel + 0.5);
  }
  
  DEFUN ("x-display-backing-store", Fx_display_backing_store,
***************
*** 4865,4870 ****
--- 4905,5106 ----
    return Qnil;
  }
  
+ static BOOL CALLBACK
+ w32_monitor_enum (HMONITOR monitor, HDC hdc, RECT *rcMonitor, LPARAM dwData)
+ {
+   Lisp_Object *monitor_list = (Lisp_Object *) dwData;
+ 
+   *monitor_list = Fcons (make_save_pointer (monitor), *monitor_list);
+ 
+   return TRUE;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list (void)
+ {
+   Lisp_Object attributes_list = Qnil, primary_monitor_attributes = Qnil;
+   Lisp_Object monitor_list = Qnil, monitor_frames, rest, frame;
+   int i, n_monitors;
+   HMONITOR *monitors;
+   struct gcpro gcpro1, gcpro2, gcpro3;
+ 
+   if (!(enum_display_monitors_fn && get_monitor_info_fn
+ 	&& monitor_from_window_fn))
+     return Qnil;
+ 
+   if (!enum_display_monitors_fn (NULL, NULL, w32_monitor_enum,
+ 				 (LPARAM) &monitor_list)
+       || NILP (monitor_list))
+     return Qnil;
+ 
+   n_monitors = 0;
+   for (rest = monitor_list; CONSP (rest); rest = XCDR (rest))
+     n_monitors++;
+ 
+   monitors = xmalloc (n_monitors * sizeof (*monitors));
+   for (i = 0; i < n_monitors; i++)
+     {
+       monitors[i] = XSAVE_POINTER (XCAR (monitor_list), 0);
+       monitor_list = XCDR (monitor_list);
+     }
+ 
+   monitor_frames = Fmake_vector (make_number (n_monitors), Qnil);
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && !EQ (frame, tip_frame))
+ 	{
+ 	  HMONITOR monitor =
+ 	    monitor_from_window_fn (FRAME_W32_WINDOW (f),
+ 				    MONITOR_DEFAULT_TO_NEAREST);
+ 
+ 	  for (i = 0; i < n_monitors; i++)
+ 	    if (monitors[i] == monitor)
+ 	      break;
+ 
+ 	  if (i < n_monitors)
+ 	    ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i)));
+ 	}
+     }
+ 
+   GCPRO3 (attributes_list, primary_monitor_attributes, monitor_frames);
+ 
+   for (i = 0; i < n_monitors; i++)
+     {
+       Lisp_Object geometry, workarea, name, attributes = Qnil;
+       HDC hdc;
+       int width_mm, height_mm;
+       struct MONITOR_INFO_EX mi;
+ 
+       mi.cbSize = sizeof (mi);
+       if (!get_monitor_info_fn (monitors[i], (struct MONITOR_INFO *) &mi))
+ 	continue;
+ 
+       hdc = CreateDCA ("DISPLAY", mi.szDevice, NULL, NULL);
+       if (hdc == NULL)
+ 	continue;
+       width_mm = GetDeviceCaps (hdc, HORZSIZE);
+       height_mm = GetDeviceCaps (hdc, VERTSIZE);
+       DeleteDC (hdc);
+ 
+       attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)),
+ 			  attributes);
+ 
+       name = DECODE_SYSTEM (make_unibyte_string (mi.szDevice,
+ 						 strlen (mi.szDevice)));
+       attributes = Fcons (Fcons (Qname, name), attributes);
+ 
+       attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 			  attributes);
+ 
+       workarea = list4i (mi.rcWork.left, mi.rcWork.top,
+ 			 mi.rcWork.right - mi.rcWork.left,
+ 			 mi.rcWork.bottom - mi.rcWork.top);
+       attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+       geometry = list4i (mi.rcMonitor.left, mi.rcMonitor.top,
+ 			 mi.rcMonitor.right - mi.rcMonitor.left,
+ 			 mi.rcMonitor.bottom - mi.rcMonitor.top);
+       attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+       if (mi.dwFlags & MONITORINFOF_PRIMARY)
+ 	primary_monitor_attributes = attributes;
+       else
+ 	attributes_list = Fcons (attributes, attributes_list);
+     }
+ 
+   if (!NILP (primary_monitor_attributes))
+     attributes_list = Fcons (primary_monitor_attributes, attributes_list);
+ 
+   UNGCPRO;
+ 
+   xfree (monitors);
+ 
+   return attributes_list;
+ }
+ 
+ static Lisp_Object
+ w32_display_monitor_attributes_list_fallback (struct w32_display_info *dpyinfo)
+ {
+   Lisp_Object geometry, workarea, frames, rest, frame, attributes = Qnil;
+   HDC hdc;
+   double mm_per_pixel;
+   int pixel_width, pixel_height, width_mm, height_mm;
+   RECT workarea_rect;
+ 
+   /* Fallback: treat (possibly) multiple physical monitors as if they
+      formed a single monitor as a whole.  This should provide a
+      consistent result at least on single monitor environments.  */
+   attributes = Fcons (Fcons (Qname, build_string ("combined screen")),
+ 		      attributes);
+ 
+   frames = Qnil;
+   FOR_EACH_FRAME (rest, frame)
+     {
+       struct frame *f = XFRAME (frame);
+ 
+       if (FRAME_W32_P (f) && !EQ (frame, tip_frame))
+ 	frames = Fcons (frame, frames);
+     }
+   attributes = Fcons (Fcons (Qframes, frames), attributes);
+ 
+   pixel_width = x_display_pixel_width (dpyinfo);
+   pixel_height = x_display_pixel_height (dpyinfo);
+ 
+   hdc = GetDC (NULL);
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, HORZSIZE)
+ 		  / GetDeviceCaps (hdc, HORZRES));
+   width_mm = pixel_width * mm_per_pixel + 0.5;
+   mm_per_pixel = ((double) GetDeviceCaps (hdc, VERTSIZE)
+ 		  / GetDeviceCaps (hdc, VERTRES));
+   height_mm = pixel_height * mm_per_pixel + 0.5;
+   ReleaseDC (NULL, hdc);
+   attributes = Fcons (Fcons (Qmm_size, list2i (width_mm, height_mm)),
+ 		      attributes);
+ 
+   /* GetSystemMetrics below may return 0 for Windows 95 or NT 4.0, but
+      we don't care.  */
+   geometry = list4i (GetSystemMetrics (SM_XVIRTUALSCREEN),
+ 		     GetSystemMetrics (SM_YVIRTUALSCREEN),
+ 		     pixel_width, pixel_height);
+   if (SystemParametersInfo (SPI_GETWORKAREA, 0, &workarea_rect, 0))
+     workarea = list4i (workarea_rect.left, workarea_rect.top,
+ 		       workarea_rect.right - workarea_rect.left,
+ 		       workarea_rect.bottom - workarea_rect.top);
+   else
+     workarea = geometry;
+   attributes = Fcons (Fcons (Qworkarea, workarea), attributes);
+ 
+   attributes = Fcons (Fcons (Qgeometry, geometry), attributes);
+ 
+   return list1 (attributes);
+ }
+ 
+ DEFUN ("w32-display-monitor-attributes-list", Fw32_display_monitor_attributes_list,
+        Sw32_display_monitor_attributes_list,
+        0, 1, 0,
+        doc: /* Return a list of physical monitor attributes on the W32 display DISPLAY.
+ 
+ The optional argument DISPLAY specifies which display to ask about.
+ DISPLAY should be either a frame or a display name (a string).
+ If omitted or nil, that stands for the selected frame's display.
+ 
+ Internal use only, use `display-monitor-attributes-list' instead.  */)
+   (Lisp_Object display)
+ {
+   struct w32_display_info *dpyinfo = check_x_display_info (display);
+   Lisp_Object attributes_list;
+ 
+   block_input ();
+   attributes_list = w32_display_monitor_attributes_list ();
+   if (NILP (attributes_list))
+     attributes_list = w32_display_monitor_attributes_list_fallback (dpyinfo);
+   unblock_input ();
+ 
+   return attributes_list;
+ }
+ 
  DEFUN ("set-message-beep", Fset_message_beep, Sset_message_beep, 1, 1, 0,
         doc: /* Set the sound generated when the bell is rung.
  SOUND is 'asterisk, 'exclamation, 'hand, 'question, 'ok, or 'silent
***************
*** 7357,7362 ****
--- 7593,7602 ----
    DEFSYM (Qcontrol, "control");
    DEFSYM (Qshift, "shift");
    DEFSYM (Qfont_param, "font-parameter");
+   DEFSYM (Qgeometry, "geometry");
+   DEFSYM (Qworkarea, "workarea");
+   DEFSYM (Qmm_size, "mm-size");
+   DEFSYM (Qframes, "frames");
    /* This is the end of symbol initialization.  */
  
  
***************
*** 7635,7640 ****
--- 7875,7881 ----
    defsubr (&Sx_display_visual_class);
    defsubr (&Sx_display_backing_store);
    defsubr (&Sx_display_save_under);
+   defsubr (&Sw32_display_monitor_attributes_list);
    defsubr (&Sx_create_frame);
    defsubr (&Sx_open_connection);
    defsubr (&Sx_close_connection);
***************
*** 7707,7712 ****
--- 7948,7955 ----
      GetProcAddress (user32_lib, "GetMonitorInfoA");
    monitor_from_window_fn = (MonitorFromWindow_Proc)
      GetProcAddress (user32_lib, "MonitorFromWindow");
+   enum_display_monitors_fn = (EnumDisplayMonitors_Proc)
+     GetProcAddress (user32_lib, "EnumDisplayMonitors");
  
    {
      HMODULE imm32_lib = GetModuleHandle ("imm32.dll");

=== modified file 'src/w32term.c'
*** src/w32term.c	2013-06-20 17:36:24 +0000
--- src/w32term.c	2013-06-20 23:51:45 +0000
***************
*** 143,148 ****
--- 143,157 ----
  #define WS_EX_LAYERED 0x80000
  #endif
  
+ /* SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN are not defined on 95 and
+    NT4.  */
+ #ifndef SM_CXVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 78
+ #endif
+ #ifndef SM_CYVIRTUALSCREEN
+ #define SM_CXVIRTUALSCREEN 79
+ #endif
+ 
  /* This is a frame waiting to be autoraised, within w32_read_socket.  */
  struct frame *pending_autoraise_frame;
  
***************
*** 519,536 ****
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, VERTRES);
!   ReleaseDC (NULL, dc);
    return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   HDC dc = GetDC (NULL);
!   int pixels = GetDeviceCaps (dc, HORZRES);
!   ReleaseDC (NULL, dc);
    return pixels;
  }
  
--- 528,551 ----
  int
  x_display_pixel_height (struct w32_display_info *dpyinfo)
  {
!   int pixels = GetSystemMetrics (SM_CYVIRTUALSCREEN);
! 
!   if (pixels == 0)
!     /* Fallback for Windows 95 or NT 4.0.  */
!     pixels = GetSystemMetrics (SM_CYSCREEN);
! 
    return pixels;
  }
  
  int
  x_display_pixel_width (struct w32_display_info *dpyinfo)
  {
!   int pixels = GetSystemMetrics (SM_CXVIRTUALSCREEN);
! 
!   if (pixels == 0)
!     /* Fallback for Windows 95 or NT 4.0.  */
!     pixels = GetSystemMetrics (SM_CXSCREEN);
! 
    return pixels;
  }
  




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

* Re: x-display-pixel-width/height inconsistency
  2013-07-02  1:30                                                                   ` YAMAMOTO Mitsuharu
@ 2013-07-02 10:38                                                                     ` martin rudalics
  2013-07-02 10:53                                                                       ` Juanma Barranquero
  0 siblings, 1 reply; 97+ messages in thread
From: martin rudalics @ 2013-07-02 10:38 UTC (permalink / raw)
  To: YAMAMOTO Mitsuharu; +Cc: Juanma Barranquero, emacs-devel

 > Sure.  Please try the following patch.

Thank you.  Unfortunately, it still doesn't apply here, probably due to
some local changes.  Juanma, can you try it?  If it applies there, I'll
adjust it manually here.

martin



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-02 10:38                                                                     ` martin rudalics
@ 2013-07-02 10:53                                                                       ` Juanma Barranquero
  2013-07-02 13:11                                                                         ` martin rudalics
  0 siblings, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-02 10:53 UTC (permalink / raw)
  To: martin rudalics; +Cc: YAMAMOTO Mitsuharu, Emacs developers

On Tue, Jul 2, 2013 at 12:38 PM, martin rudalics <rudalics@gmx.at> wrote:

> Thank you.  Unfortunately, it still doesn't apply here, probably due to
> some local changes.  Juanma, can you try it?  If it applies there, I'll
> adjust it manually here.

I already tested it. Applies OK, seems to work, but unfortunately I
don't have a multi-monitor setup. I'd say let's commit it so it can be
tested by more people.

   J



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-02 10:53                                                                       ` Juanma Barranquero
@ 2013-07-02 13:11                                                                         ` martin rudalics
  2013-07-02 14:05                                                                           ` Juanma Barranquero
  0 siblings, 1 reply; 97+ messages in thread
From: martin rudalics @ 2013-07-02 13:11 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: YAMAMOTO Mitsuharu, Emacs developers

 > I already tested it. Applies OK, seems to work, but unfortunately I
 > don't have a multi-monitor setup. I'd say let's commit it so it can be
 > tested by more people.

I don't have a multi-monitor setup either.  Does the workarea come up
correctly, i.e., does it match a maximized frame?

martin



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-02 13:11                                                                         ` martin rudalics
@ 2013-07-02 14:05                                                                           ` Juanma Barranquero
  2013-07-03  9:27                                                                             ` martin rudalics
  0 siblings, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-02 14:05 UTC (permalink / raw)
  To: martin rudalics; +Cc: YAMAMOTO Mitsuharu, Emacs developers

> I don't have a multi-monitor setup either.  Does the workarea come up
> correctly, i.e., does it match a maximized frame?

display-monitor-attributes-list returns geometry = (0 0 1920 1080) and
workarea = (0 0 1920 1040)

Now, according to frame-pixel-(width|height):

- (fullscreen . fullscreen) frame = 1920 x 1060
- (fullscreen . maximized) frame = 1904 x 982
- maximized frame (Windows window manager style, i.e., clicking on the
maximize button) = 1920 x 998



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-02 14:05                                                                           ` Juanma Barranquero
@ 2013-07-03  9:27                                                                             ` martin rudalics
  2013-07-03 10:49                                                                               ` Juanma Barranquero
  0 siblings, 1 reply; 97+ messages in thread
From: martin rudalics @ 2013-07-03  9:27 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: YAMAMOTO Mitsuharu, Emacs developers

 > display-monitor-attributes-list returns geometry = (0 0 1920 1080) and
 > workarea = (0 0 1920 1040)
 >
 > Now, according to frame-pixel-(width|height):
 >
 > - (fullscreen . fullscreen) frame = 1920 x 1060
 > - (fullscreen . maximized) frame = 1904 x 982
 > - maximized frame (Windows window manager style, i.e., clicking on the
 > maximize button) = 1920 x 998

Could you please add the function below, make a frame, and call the
function for a fullscreen and maximized frame with both CLIENT nil and
t.  I'd like to compare these rather than what frame-pixel-... return.

Thanks, martin


DEFUN ("w32-frame-rect", Fw32_frame_rect, Sw32_frame_rect, 0, 2, 0,
        doc: /* Return boundary rectangle of FRAME in screen coordinates.
FRAME must be a live frame and defaults to the selected one.

The boundary rectangle is a list of four elements, specifying the left,
top, right and bottom screen coordinates of FRAME including menu and
title bar and decorations.  Optional argument CLIENT non-nil means to
return the boundaries of the client rectangle which excludes menu and
title bar and decorations.  */)
   (Lisp_Object frame, Lisp_Object client)
{
   struct frame *f = decode_live_frame (frame);
   RECT rect;

   if (!NILP (client))
     GetClientRect (FRAME_W32_WINDOW (f), &rect);
   else
     GetWindowRect (FRAME_W32_WINDOW (f), &rect);

   return list4 (make_number (rect.left), make_number (rect.top),
		make_number (rect.right), make_number (rect.bottom));
}



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-03  9:27                                                                             ` martin rudalics
@ 2013-07-03 10:49                                                                               ` Juanma Barranquero
  2013-07-03 12:44                                                                                 ` martin rudalics
  0 siblings, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-03 10:49 UTC (permalink / raw)
  To: martin rudalics; +Cc: YAMAMOTO Mitsuharu, Emacs developers

On Wed, Jul 3, 2013 at 11:27 AM, martin rudalics <rudalics@gmx.at> wrote:

> Could you please add the function below, make a frame, and call the
> function for a fullscreen and maximized frame with both CLIENT nil and
> t.  I'd like to compare these rather than what frame-pixel-... return.

In these results, the first list is CLIENT=nil, second is CLIENT=t

- (fullscreen . fullscreen) => ((0 0 1920 1080) (0 0 1920 1060))
- (fullscreen . maximized) => ((0 0 1920 1040) (0 0 1904 982))
- truly maximized frame => ((-8 -8 1928 1048) (0 0 1920 998))

   J



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-03 10:49                                                                               ` Juanma Barranquero
@ 2013-07-03 12:44                                                                                 ` martin rudalics
  2013-07-03 13:43                                                                                   ` Juanma Barranquero
  0 siblings, 1 reply; 97+ messages in thread
From: martin rudalics @ 2013-07-03 12:44 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: YAMAMOTO Mitsuharu, Emacs developers

 > - (fullscreen . fullscreen) => ((0 0 1920 1080) (0 0 1920 1060))
 > - (fullscreen . maximized) => ((0 0 1920 1040) (0 0 1904 982))
 > - truly maximized frame => ((-8 -8 1928 1048) (0 0 1920 998))

Thanks.  Combined with the one you reported earlier, namely

 > display-monitor-attributes-list returns geometry = (0 0 1920 1080) and
 > workarea = (0 0 1920 1040)

this makes sense.

Yamamoto, could you please install this part?  Maybe we find someone who
uses multiple monitors on Windows.

Thanks, martin



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-03 12:44                                                                                 ` martin rudalics
@ 2013-07-03 13:43                                                                                   ` Juanma Barranquero
  2013-07-04  9:34                                                                                     ` martin rudalics
  2013-07-04 10:28                                                                                     ` YAMAMOTO Mitsuharu
  0 siblings, 2 replies; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-03 13:43 UTC (permalink / raw)
  To: martin rudalics; +Cc: YAMAMOTO Mitsuharu, Emacs developers

> Yamamoto, could you please install this part?  Maybe we find someone who
> uses multiple monitors on Windows.

Also, please move the defsubr for Sw32_display_monitor_attributes_list
after the W32-specific header. Thanks.

Martin, what about your w32-frame-rect? It would be useful to have
something like that (generalized for X, NS, etc.)

   J



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-03 13:43                                                                                   ` Juanma Barranquero
@ 2013-07-04  9:34                                                                                     ` martin rudalics
       [not found]                                                                                       ` <5987E3>
  2013-07-04 22:32                                                                                       ` Juanma Barranquero
  2013-07-04 10:28                                                                                     ` YAMAMOTO Mitsuharu
  1 sibling, 2 replies; 97+ messages in thread
From: martin rudalics @ 2013-07-04  9:34 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: YAMAMOTO Mitsuharu, Emacs developers

 > Martin, what about your w32-frame-rect? It would be useful to have
 > something like that (generalized for X, NS, etc.)

On Windows frame and client rectangle include the toolbar.  So I'm not
sure how to generalize this conveniently.

martin



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-03 13:43                                                                                   ` Juanma Barranquero
  2013-07-04  9:34                                                                                     ` martin rudalics
@ 2013-07-04 10:28                                                                                     ` YAMAMOTO Mitsuharu
  1 sibling, 0 replies; 97+ messages in thread
From: YAMAMOTO Mitsuharu @ 2013-07-04 10:28 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: martin rudalics, Emacs developers

>>>>> On Wed, 3 Jul 2013 15:43:35 +0200, Juanma Barranquero <lekktu@gmail.com> said:

>> Yamamoto, could you please install this part?  Maybe we find
>> someone who uses multiple monitors on Windows.

> Also, please move the defsubr for
> Sw32_display_monitor_attributes_list after the W32-specific
> header. Thanks.

Done.  Thanks for testing.

				     YAMAMOTO Mitsuharu
				mituharu@math.s.chiba-u.ac.jp



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-04  9:34                                                                                     ` martin rudalics
       [not found]                                                                                       ` <5987E3>
@ 2013-07-04 22:32                                                                                       ` Juanma Barranquero
  2013-07-05  7:44                                                                                         ` martin rudalics
  2013-07-05  9:34                                                                                         ` Jan Djärv
  1 sibling, 2 replies; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-04 22:32 UTC (permalink / raw)
  To: martin rudalics; +Cc: YAMAMOTO Mitsuharu, Emacs developers

> On Windows frame and client rectangle include the toolbar.  So I'm not
> sure how to generalize this conveniently.

Oh.

Anyway, backtracking a bit in this thread... We were talking about
multi-monitors and client sizes, etc. because someone proposed to
automatically detect when desktop is restoring frames in a different
display/monitor configuration and make sure that the frames were
visible.

But, OTOH, it is entirely possible that the user is saving the desktop
with some frames only partially visible. If you have many, and some of
them are less used, you can set them aside so only a fraction of the
frame is shown, which makes them accessible without taking too much
screen space. So, IMO, the only thing that makes sense is to
move/resize a frame while restoring when that frame is entirely
outside the current viewing area. Or, perhaps, when the caption is
(because in many/most/all? window managers, you can mouse-drag a
window only from its caption).

Of course, there's no way to know the caption height (in pixels) from
inside Emacs, I think, so in the end it's all an ugly heuristics: the
top of the frame is some arbitrary number of pixels inside the viewing
area. Or is there a better way?

   J



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-04 22:32                                                                                       ` Juanma Barranquero
@ 2013-07-05  7:44                                                                                         ` martin rudalics
  2013-07-05  9:32                                                                                           ` Juanma Barranquero
  2013-07-05  9:34                                                                                         ` Jan Djärv
  1 sibling, 1 reply; 97+ messages in thread
From: martin rudalics @ 2013-07-05  7:44 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: YAMAMOTO Mitsuharu, Emacs developers

 > But, OTOH, it is entirely possible that the user is saving the desktop
 > with some frames only partially visible. If you have many, and some of
 > them are less used, you can set them aside so only a fraction of the
 > frame is shown, which makes them accessible without taking too much
 > screen space.

Perfectly reasonable, yes.

 > So, IMO, the only thing that makes sense is to
 > move/resize a frame while restoring when that frame is entirely
 > outside the current viewing area.

The Windows window manager does that automatically, IIRC.

 > Or, perhaps, when the caption is
 > (because in many/most/all? window managers, you can mouse-drag a
 > window only from its caption).
 >
 > Of course, there's no way to know the caption height (in pixels) from
 > inside Emacs, I think, so in the end it's all an ugly heuristics: the
 > top of the frame is some arbitrary number of pixels inside the viewing
 > area. Or is there a better way?

I think that once users have the workarea from Yamamoto's function, they
can easily adjust frame positions and sizes in a hook.  So I wouldn't
care about this problem from the POV of `desktop-read' any more.  Let's
see whether this really could become an issue.

martin



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05  7:44                                                                                         ` martin rudalics
@ 2013-07-05  9:32                                                                                           ` Juanma Barranquero
  0 siblings, 0 replies; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-05  9:32 UTC (permalink / raw)
  To: martin rudalics; +Cc: YAMAMOTO Mitsuharu, Emacs developers

On Fri, Jul 5, 2013 at 9:44 AM, martin rudalics <rudalics@gmx.at> wrote:

> The Windows window manager does that automatically, IIRC.

I'm not so sure. I use a program that, when put far to one side of the
screen, routinely shows warning dialogs outside it.

> I think that once users have the workarea from Yamamoto's function, they
> can easily adjust frame positions and sizes in a hook.  So I wouldn't
> care about this problem from the POV of `desktop-read' any more.  Let's
> see whether this really could become an issue.

OK, though I suspect some people will want it as an option and not a hook.

    J



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-04 22:32                                                                                       ` Juanma Barranquero
  2013-07-05  7:44                                                                                         ` martin rudalics
@ 2013-07-05  9:34                                                                                         ` Jan Djärv
  2013-07-05  9:41                                                                                           ` Juanma Barranquero
  1 sibling, 1 reply; 97+ messages in thread
From: Jan Djärv @ 2013-07-05  9:34 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers


5 jul 2013 kl. 00:32 skrev Juanma Barranquero <lekktu@gmail.com>:

>> On Windows frame and client rectangle include the toolbar.  So I'm not
>> sure how to generalize this conveniently.
> 
> Oh.
> 
> Anyway, backtracking a bit in this thread... We were talking about
> multi-monitors and client sizes, etc. because someone proposed to
> automatically detect when desktop is restoring frames in a different
> display/monitor configuration and make sure that the frames were
> visible.
> 
> But, OTOH, it is entirely possible that the user is saving the desktop
> with some frames only partially visible. If you have many, and some of
> them are less used, you can set them aside so only a fraction of the
> frame is shown, which makes them accessible without taking too much
> screen space. So, IMO, the only thing that makes sense is to
> move/resize a frame while restoring when that frame is entirely
> outside the current viewing area. Or, perhaps, when the caption is
> (because in many/most/all? window managers, you can mouse-drag a
> window only from its caption).
> 
> Of course, there's no way to know the caption height (in pixels) from
> inside Emacs, I think, so in the end it's all an ugly heuristics: the
> top of the frame is some arbitrary number of pixels inside the viewing
> area. Or is there a better way?
> 

W32 is the odd duck here, frame-parameter top in NS and X refers to the outer edge of the window including caption height, i.e. the real top of the frame.  We do know caption height in Emacs, but only at the C level.  W32 has to be fixed to behave like the other ports if it does not already.

	Jan D.





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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05  9:34                                                                                         ` Jan Djärv
@ 2013-07-05  9:41                                                                                           ` Juanma Barranquero
  2013-07-05 11:25                                                                                             ` Jan Djärv
  0 siblings, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-05  9:41 UTC (permalink / raw)
  To: Jan Djärv; +Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers

On Fri, Jul 5, 2013 at 11:34 AM, Jan Djärv <jan.h.d@swipnet.se> wrote:

> W32 is the odd duck here, frame-parameter top in NS and X
> refers to the outer edge of the window including caption height,
> i.e. the real top of the frame.

Sorry, I don't understand. AFAIK, the `top' frame parameter in Windows
also refers to the real top of the frame, but I fail to see the
relationship between that fact and what I was discussing.

   J



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05  9:41                                                                                           ` Juanma Barranquero
@ 2013-07-05 11:25                                                                                             ` Jan Djärv
  2013-07-05 11:56                                                                                               ` Juanma Barranquero
  0 siblings, 1 reply; 97+ messages in thread
From: Jan Djärv @ 2013-07-05 11:25 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers

Hello.

5 jul 2013 kl. 11:41 skrev Juanma Barranquero <lekktu@gmail.com>:

> On Fri, Jul 5, 2013 at 11:34 AM, Jan Djärv <jan.h.d@swipnet.se> wrote:
> 
>> W32 is the odd duck here, frame-parameter top in NS and X
>> refers to the outer edge of the window including caption height,
>> i.e. the real top of the frame.
> 
> Sorry, I don't understand. AFAIK, the `top' frame parameter in Windows
> also refers to the real top of the frame, but I fail to see the
> relationship between that fact and what I was discussing.

You said:

> So, IMO, the only thing that makes sense is to
> move/resize a frame while restoring when that frame is entirely
> outside the current viewing area. Or, perhaps, when the caption is
> (because in many/most/all? window managers, you can mouse-drag a
> window only from its caption).
> 
> Of course, there's no way to know the caption height (in pixels) from
> inside Emacs, I think, so in the end it's all an ugly heuristics: the
> top of the frame is some arbitrary number of pixels inside the viewing
> area. Or is there a better way?
> 

You don't need "some arbitrary number of pixels".  As I outlined before, if top/left is inside, put the frame there, otherwise put it at some default position.
Another possibility is that the display-monitor-attributes-list includes a list of all frame belonging to a particular monitor.  If that monitor is still available, restore the frame there, otherwise not.

	Jan D.




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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05 11:25                                                                                             ` Jan Djärv
@ 2013-07-05 11:56                                                                                               ` Juanma Barranquero
  2013-07-05 12:12                                                                                                 ` Jan Djärv
  0 siblings, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-05 11:56 UTC (permalink / raw)
  To: Jan Djärv; +Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers

On Fri, Jul 5, 2013 at 1:25 PM, Jan Djärv <jan.h.d@swipnet.se> wrote:

> You don't need "some arbitrary number of pixels".  As I outlined before, if top/left is inside, put the frame there, otherwise put it at some default position.

The caption could be inside by one pixel, and that would be almost
invisible and/or hard to drag.

> Another possibility is that the display-monitor-attributes-list includes
> a list of all frame belonging to a particular monitor.

Yes.

> If that monitor is still available, restore the frame there, otherwise not.

How would  I know that? Are you proposing that I save also the list of
monitors? Note that the monitor name alone is not a good identifier,
because if I always use only one, but I switch monitors between saving
and restoring, the physical dimensions will potentially be different,
but the monitor will still be called "\\\\.\\DISPLAY1".

    J



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05 11:56                                                                                               ` Juanma Barranquero
@ 2013-07-05 12:12                                                                                                 ` Jan Djärv
  2013-07-05 12:16                                                                                                   ` Juanma Barranquero
  2013-07-05 15:27                                                                                                   ` Drew Adams
  0 siblings, 2 replies; 97+ messages in thread
From: Jan Djärv @ 2013-07-05 12:12 UTC (permalink / raw)
  To: Juanma Barranquero; +Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers

Hello.

5 jul 2013 kl. 13:56 skrev Juanma Barranquero <lekktu@gmail.com>:

> On Fri, Jul 5, 2013 at 1:25 PM, Jan Djärv <jan.h.d@swipnet.se> wrote:
> 
>> You don't need "some arbitrary number of pixels".  As I outlined before, if top/left is inside, put the frame there, otherwise put it at some default position.
> 
> The caption could be inside by one pixel, and that would be almost
> invisible and/or hard to drag.

This is also a W32:ism, as other systems allow moving of frames without using the caption, so since this only is a problem on W32, you could make some W32-specific solution that you think is best.

> 
>> Another possibility is that the display-monitor-attributes-list includes
>> a list of all frame belonging to a particular monitor.
> 
> Yes.
> 
>> If that monitor is still available, restore the frame there, otherwise not.
> 
> How would  I know that? Are you proposing that I save also the list of
> monitors? Note that the monitor name alone is not a good identifier,
> because if I always use only one, but I switch monitors between saving
> and restoring, the physical dimensions will potentially be different,
> but the monitor will still be called "\\\\.\\DISPLAY1".

I was thinking of the monitor geometries.  But as I said before, top/left availability is fine by me.

	Jan D.





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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05 12:12                                                                                                 ` Jan Djärv
@ 2013-07-05 12:16                                                                                                   ` Juanma Barranquero
  2013-07-05 15:30                                                                                                     ` Drew Adams
  2013-07-05 15:27                                                                                                   ` Drew Adams
  1 sibling, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-05 12:16 UTC (permalink / raw)
  To: Jan Djärv; +Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers

On Fri, Jul 5, 2013 at 2:12 PM, Jan Djärv <jan.h.d@swipnet.se> wrote:

> This is also a W32:ism, as other systems allow moving of frames without
> using the caption

On Windows it is perfectly possible to move a "frame" without the
mouse, using keyboard shortcuts, even if it is outside the screen. But
I bet many users don't remember how to do it.

   J



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

* RE: x-display-pixel-width/height inconsistency
  2013-07-05 12:12                                                                                                 ` Jan Djärv
  2013-07-05 12:16                                                                                                   ` Juanma Barranquero
@ 2013-07-05 15:27                                                                                                   ` Drew Adams
  1 sibling, 0 replies; 97+ messages in thread
From: Drew Adams @ 2013-07-05 15:27 UTC (permalink / raw)
  To: Jan Djärv, Juanma Barranquero
  Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers

> > The caption could be inside by one pixel, and that would be almost
> > invisible and/or hard to drag.
> 
> This is also a W32:ism, as other systems allow moving of frames without
> using the caption, so since this only is a problem on W32, you could make
> some W32-specific solution that you think is best.

(Apologies if I misunderstand the topic; I have not been following it.)

You can move any MS Windows window, including an Emacs frame, without
using the title bar, which I guess is what you mean by the caption.
It does not matter whether the window is completely off the screen or not.

And you can do that from Emacs as well.



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

* RE: x-display-pixel-width/height inconsistency
  2013-07-05 12:16                                                                                                   ` Juanma Barranquero
@ 2013-07-05 15:30                                                                                                     ` Drew Adams
  2013-07-05 15:53                                                                                                       ` Juanma Barranquero
  0 siblings, 1 reply; 97+ messages in thread
From: Drew Adams @ 2013-07-05 15:30 UTC (permalink / raw)
  To: Juanma Barranquero, Jan Djärv
  Cc: martin rudalics, YAMAMOTO Mitsuharu, Emacs developers

> > This is also a W32:ism, as other systems allow moving of frames without
> > using the caption
> 
> On Windows it is perfectly possible to move a "frame" without the
> mouse, using keyboard shortcuts, even if it is outside the screen. But
> I bet many users don't remember how to do it.

If this is a problem then just provide an Emacs command to do it.
Not a big deal: Let the user choose the frame (e.g., by name).
If it is off-screen then move it on-screen.



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05 15:30                                                                                                     ` Drew Adams
@ 2013-07-05 15:53                                                                                                       ` Juanma Barranquero
  2013-07-05 16:58                                                                                                         ` Drew Adams
  0 siblings, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-05 15:53 UTC (permalink / raw)
  To: Drew Adams
  Cc: martin rudalics, Jan Djärv, YAMAMOTO Mitsuharu,
	Emacs developers

On Fri, Jul 5, 2013 at 5:30 PM, Drew Adams <drew.adams@oracle.com> wrote:

> If it is off-screen then move it on-screen.

Just detecting if it is off-screen isn't trivial with multiple
monitor. By using three of them side-by-side but not perfectly
aligned, it would be possible to have a window (an Emacs frame) that
is visible, and yet has its four corners outside any monitor's
displaying area.

Anyway, I'm against adding a command to move a frame on-screen. As
part of automatic restoration, perhaps, because restoration does not
require user interaction. But if a frame is off-screen and the user
wants it on-screen, please dear user, learn to use Windows more
effectively.

    J



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

* RE: x-display-pixel-width/height inconsistency
  2013-07-05 15:53                                                                                                       ` Juanma Barranquero
@ 2013-07-05 16:58                                                                                                         ` Drew Adams
  2013-07-06 14:48                                                                                                           ` Juanma Barranquero
  0 siblings, 1 reply; 97+ messages in thread
From: Drew Adams @ 2013-07-05 16:58 UTC (permalink / raw)
  To: Juanma Barranquero
  Cc: martin rudalics, Jan Djärv, YAMAMOTO Mitsuharu,
	Emacs developers

> > If it is off-screen then move it on-screen.
> 
> Just detecting if it is off-screen isn't trivial with multiple
> monitor. By using three of them side-by-side but not perfectly
> aligned, it would be possible to have a window (an Emacs frame) that
> is visible, and yet has its four corners outside any monitor's
> displaying area.

OK.  But for other cases?  No reason to let the ideal become the enemy
of the good.

> Anyway, I'm against adding a command to move a frame on-screen. As
> part of automatic restoration, perhaps, because restoration does not
> require user interaction. But if a frame is off-screen and the user
> wants it on-screen, please dear user, learn to use Windows more
> effectively.

No - please, dear Emacs, learn to help lost users. ;-)

I don't feel strongly about it, but I guess I disagree.  I can imagine
people who use Emacs on multiple platforms, including MS Windows, and
who never become True Winistas.

In addition, beyond Emacs, I would even guess that most Windows users
have no idea how to move a window back on screen.  Google "how to move
window back onto screen"...

And they generally do not need such knowledge.  Losing a window
off-screen does not happen every 30 minutes.

I think you mentioned that your use of MS Windows is mainly command-line
use.  That's great, but it is hardly the case of most Windows users.  (I
would even guess it is hardly the case for most Windows users of Emacs.)

In sum, most Emacs users, whether on MS Windows or not, will not guess
how to move a frame back onto the screen.  And most Windows users will
not know how to do so outside Emacs.

And it is trivial to provide a command that lets a user select a frame
and then move it around until s?he sees it - or just move it to, say,
top: 0, left: 0.

FWIW - In frame-cmds.el I have long had commands
`move-frame-to-screen-(top|bottom|left|right)', with suggested bindings
 `M-S-v', `C-S-v', `C-S-prior', and `C-S-next'.

These all read a frame name using completion (default: selected frame),
then move that frame to the corresponding screen edge.  With a numeric
prefix arg they offset it that many chars from the edge.

(And there are repeatable commands that move the selected frame in each
direction - suggested repeatable bindings: `M-(up|down|left|right)'.

While such commands can be used to get a frame back on screen, I've now
added `move-frame-to-screen-top-left' (suggested binding: `C-S-home'),
to move a frame you choose to the top, left screen corner.

(No idea what this means for multiple monitors, but presumably the
off-all-monitors frame you describe would show up at the top left of
one of the monitors.)



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

* Re: x-display-pixel-width/height inconsistency
  2013-07-05 16:58                                                                                                         ` Drew Adams
@ 2013-07-06 14:48                                                                                                           ` Juanma Barranquero
  2013-07-06 19:25                                                                                                             ` Drew Adams
  0 siblings, 1 reply; 97+ messages in thread
From: Juanma Barranquero @ 2013-07-06 14:48 UTC (permalink / raw)
  To: Drew Adams
  Cc: martin rudalics, Jan Djärv, YAMAMOTO Mitsuharu,
	Emacs developers

On Fri, Jul 5, 2013 at 6:58 PM, Drew Adams <drew.adams@oracle.com> wrote:

> OK.  But for other cases?  No reason to let the ideal become the enemy
> of the good.

Well, obviously if we go for detecting that kind of situation, that
some corner cases are difficult will not stop us from fixing the
common ones.

> No - please, dear Emacs, learn to help lost users. ;-)

Emacs should not be a generic Windows-learning tool, and having a
window displayed outside the monitor is uncommon, but absolutely not
Emacs-specific.

> In addition, beyond Emacs, I would even guess that most Windows users
> have no idea how to move a window back on screen.  Google "how to move
> window back onto screen"...

So that's what they should do if they find themselves in that
circumstance. Is what I did, after all...

> And they generally do not need such knowledge.  Losing a window
> off-screen does not happen every 30 minutes.

Losing a window off-screen *because* of frame restoration should not
happen every 30 minutes, either. It will be uncommon unless you happen
to save & restore often in quite different monitor configurations, and
if that's the case, and even if desktop.el tries its best to help, the
user should be prepared to accept some oddities (or some .emacs
tweaking).

> I think you mentioned that your use of MS Windows is mainly command-line use.

No, I'm a heavy user of command line (for example, I almost never copy
or move files with the Windows Explorer), but I'm also a heavy user of
the Windows GUI.

>  That's great, but it is hardly the case of most Windows users.  (I
> would even guess it is hardly the case for most Windows users of Emacs.)

That's an argument *for* them to know about moving windows back into
the viewing area, not against.

    J



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

* RE: x-display-pixel-width/height inconsistency
  2013-07-06 14:48                                                                                                           ` Juanma Barranquero
@ 2013-07-06 19:25                                                                                                             ` Drew Adams
  0 siblings, 0 replies; 97+ messages in thread
From: Drew Adams @ 2013-07-06 19:25 UTC (permalink / raw)
  To: Juanma Barranquero
  Cc: martin rudalics, Jan Djärv, YAMAMOTO Mitsuharu,
	Emacs developers

> > No - please, dear Emacs, learn to help lost users. ;-)
> 
> Emacs should not be a generic Windows-learning tool,

I certainly don't disagree there - but no one suggested that.

I said nothing about Emacs teaching users the Windows solution for the
problem cited.  I proposed a simple Emacs solution for it - and not
dependent on the platform.

> and having a window displayed outside the monitor is uncommon,
> but absolutely not Emacs-specific.

Agreed again.

But if a user uses Emacs with multiple frames, and especially if s?he
restores things using Desktop (which might never be 100% perfect), s?he
could benefit from a simple Emacs command to bring a lost frame back
to the playground.  And especially if the desktop-restoring session
involves a different monitor setup, resolution, platform...

> > In addition, beyond Emacs, I would even guess that most Windows users
> > have no idea how to move a window back on screen.  Google "how to move
> > window back onto screen"...
> 
> So that's what they should do if they find themselves in that
> circumstance. Is what I did, after all...

As do I, each time it happens (which is rare, which is why I forget).

But just because Windows does not make it obvious how to do this
(Google does, but not MS Windows) is no reason why Emacs should not do
so.  Emacs is self-documenting in a way that Windows is not, and it
can be easy for a user to find the open-sesame for this if we provide
an Emacs command for it.

> > And they generally do not need such knowledge.  Losing a window
> > off-screen does not happen every 30 minutes.
> 
> Losing a window off-screen *because* of frame restoration should not
> happen every 30 minutes, either.

Agreed.  I don't see this potential problem or its solution as being
related only to desktop restoration.  It is somewhat related but
essentially OT.

> It will be uncommon unless you happen to save & restore often in
> quite different monitor configurations, and if that's the case,
> and even if desktop.el tries its best to help,

Yes, we agree about the cases where one might lose a frame off-screen.

> the user should be prepared to accept some oddities (or some .emacs
> tweaking).

That's where we disagree.  Well, I don't actually disagree with that
statement, but I think that wrt an off-screen frame we can trivially
do something to help.

> > I think you mentioned that your use of MS Windows is mainly
> > command-line use.
> 
> No, I'm a heavy user of command line (for example, I almost never copy
> or move files with the Windows Explorer), but I'm also a heavy user of
> the Windows GUI.
> 
> >  That's great, but it is hardly the case of most Windows users.  (I
> > would even guess it is hardly the case for most Windows users of Emacs.)
> 
> That's an argument *for* them to know about moving windows back into
> the viewing area, not against.

No one argues that it is wrong or not useful for a user to know that.

What I disagree with is this previous statement of yours:

> But if a frame is off-screen and the user wants it on-screen, please
> dear user, learn to use Windows more effectively.

It can help the user to learn more about Windows, but that should not
be our only response.  Why?  Because Emacs can do better.  In this case,
better than Windows and just as well as Google.

I don't know whether the same problem of losing frames off screen exists
potentially for platforms besides Windows (I'm guessing yes).  But I do
know that there is a trivial, any-platform Emacs solution for bringing
such stray frames back to the playground.

I don't see this (relatively minor) problem as a Windows problem.  I see
it as a potential (and minor) gotcha that an Emacs user might get bit by,
and one for which there is a simple Emacs solution.



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

end of thread, other threads:[~2013-07-06 19:25 UTC | newest]

Thread overview: 97+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-21  0:58 x-display-pixel-width/height inconsistency grischka
2013-03-21  1:05 ` YAMAMOTO Mitsuharu
2013-03-21  1:09   ` grischka
2013-03-21  1:44     ` YAMAMOTO Mitsuharu
2013-03-21 23:29       ` YAMAMOTO Mitsuharu
2013-03-22 10:33         ` Eli Zaretskii
2013-03-23  0:32           ` YAMAMOTO Mitsuharu
2013-03-23  6:15             ` Eli Zaretskii
2013-03-23 13:35               ` Jan Djärv
2013-03-23 23:58               ` YAMAMOTO Mitsuharu
2013-03-24  3:53                 ` Eli Zaretskii
2013-03-24  4:36                   ` YAMAMOTO Mitsuharu
2013-03-24 16:19                     ` Eli Zaretskii
2013-04-27  5:13                     ` YAMAMOTO Mitsuharu
2013-04-27  8:04                       ` Jan Djärv
2013-04-28  1:40                         ` YAMAMOTO Mitsuharu
2013-04-28 17:16                           ` Jan D.
2013-04-29  2:27                             ` YAMAMOTO Mitsuharu
2013-04-29  2:42                               ` YAMAMOTO Mitsuharu
2013-05-01  9:58                               ` Jan Djärv
2013-05-02  4:09                                 ` YAMAMOTO Mitsuharu
2013-05-06  1:04                                   ` YAMAMOTO Mitsuharu
2013-05-06  1:55                                     ` Stefan Monnier
2013-05-06  6:15                                       ` YAMAMOTO Mitsuharu
2013-05-06 13:37                                         ` Stefan Monnier
2013-05-08 10:46                                         ` YAMAMOTO Mitsuharu
2013-05-08 11:24                                           ` YAMAMOTO Mitsuharu
2013-05-08 17:41                                           ` Eli Zaretskii
2013-05-09  0:09                                             ` YAMAMOTO Mitsuharu
2013-05-09  1:52                                               ` Glenn Morris
2013-05-09  3:19                                                 ` YAMAMOTO Mitsuharu
2013-05-09  6:27                                                   ` Glenn Morris
2013-05-09  2:53                                               ` Eli Zaretskii
2013-05-09  8:14                                               ` Jan Djärv
2013-05-09  8:43                                                 ` YAMAMOTO Mitsuharu
2013-05-09 15:18                                                   ` Jan Djärv
2013-05-09 20:03                                               ` Eli Zaretskii
2013-05-09 21:28                                                 ` Stefan Monnier
2013-05-10  6:00                                                 ` YAMAMOTO Mitsuharu
2013-05-10  6:05                                                   ` YAMAMOTO Mitsuharu
2013-05-10  7:06                                                   ` Eli Zaretskii
2013-05-10  7:47                                                     ` YAMAMOTO Mitsuharu
2013-05-10  8:41                                                       ` Eli Zaretskii
2013-05-10  8:55                                                         ` YAMAMOTO Mitsuharu
2013-05-10  9:15                                                           ` Eli Zaretskii
2013-05-10  9:27                                                             ` YAMAMOTO Mitsuharu
2013-05-14 10:39                                                               ` YAMAMOTO Mitsuharu
2013-07-01  6:49                                                                 ` martin rudalics
2013-07-02  1:30                                                                   ` YAMAMOTO Mitsuharu
2013-07-02 10:38                                                                     ` martin rudalics
2013-07-02 10:53                                                                       ` Juanma Barranquero
2013-07-02 13:11                                                                         ` martin rudalics
2013-07-02 14:05                                                                           ` Juanma Barranquero
2013-07-03  9:27                                                                             ` martin rudalics
2013-07-03 10:49                                                                               ` Juanma Barranquero
2013-07-03 12:44                                                                                 ` martin rudalics
2013-07-03 13:43                                                                                   ` Juanma Barranquero
2013-07-04  9:34                                                                                     ` martin rudalics
     [not found]                                                                                       ` <5987E3>
2013-07-04 22:32                                                                                       ` Juanma Barranquero
2013-07-05  7:44                                                                                         ` martin rudalics
2013-07-05  9:32                                                                                           ` Juanma Barranquero
2013-07-05  9:34                                                                                         ` Jan Djärv
2013-07-05  9:41                                                                                           ` Juanma Barranquero
2013-07-05 11:25                                                                                             ` Jan Djärv
2013-07-05 11:56                                                                                               ` Juanma Barranquero
2013-07-05 12:12                                                                                                 ` Jan Djärv
2013-07-05 12:16                                                                                                   ` Juanma Barranquero
2013-07-05 15:30                                                                                                     ` Drew Adams
2013-07-05 15:53                                                                                                       ` Juanma Barranquero
2013-07-05 16:58                                                                                                         ` Drew Adams
2013-07-06 14:48                                                                                                           ` Juanma Barranquero
2013-07-06 19:25                                                                                                             ` Drew Adams
2013-07-05 15:27                                                                                                   ` Drew Adams
2013-07-04 10:28                                                                                     ` YAMAMOTO Mitsuharu
2013-05-10  7:44                                                   ` Jan Djärv
2013-04-28  1:48                       ` YAMAMOTO Mitsuharu
  -- strict thread matches above, loose matches on Subject: below --
2013-03-19  0:39 YAMAMOTO Mitsuharu
2013-03-19  1:34 ` Leo Liu
2013-03-19  4:54   ` Xue Fuqiao
2013-03-19 15:41     ` Drew Adams
2013-03-19 15:51       ` Leo Liu
2013-03-19 15:58         ` Drew Adams
2013-03-20  0:55           ` Leo Liu
2013-03-19 22:25 ` YAMAMOTO Mitsuharu
2013-03-19 23:15   ` Dmitry Gutov
2013-03-19 23:52     ` YAMAMOTO Mitsuharu
2013-03-20  0:12       ` Dmitry Gutov
2013-03-20  0:20         ` YAMAMOTO Mitsuharu
2013-03-20  1:41           ` Dmitry Gutov
2013-03-20  3:58             ` YAMAMOTO Mitsuharu
2013-03-20 14:05               ` Dmitry Gutov
2013-03-20 23:28                 ` YAMAMOTO Mitsuharu
2013-03-21  1:27                   ` Dmitry Gutov
2013-03-21  1:51                     ` YAMAMOTO Mitsuharu
2013-03-21  2:43                       ` Dmitry Gutov
2013-03-21  3:47                         ` YAMAMOTO Mitsuharu
2013-03-21  4:22                           ` YAMAMOTO Mitsuharu

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).