* 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 x-display-pixel-width/height inconsistency 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 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-19 0:39 x-display-pixel-width/height inconsistency 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-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-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: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 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 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-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: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-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 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 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 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 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
[parent not found: <5987E3>]
* 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: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
* 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-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-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-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
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-19 0:39 x-display-pixel-width/height inconsistency 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 -- strict thread matches above, loose matches on Subject: below -- 2013-03-21 0:58 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
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).