diff options
| author | YAMAMOTO Mitsuharu | 2013-05-07 10:12:22 +0900 |
|---|---|---|
| committer | YAMAMOTO Mitsuharu | 2013-05-07 10:12:22 +0900 |
| commit | 4e3f92301d062dcfa29128e7df5058e6e21dcb07 (patch) | |
| tree | 62e27bb22b1a48cbd52973548ef16e8649eb4f02 | |
| parent | af69a478c07658772615402f021601c5a3c118d9 (diff) | |
| download | emacs-4e3f92301d062dcfa29128e7df5058e6e21dcb07.tar.gz emacs-4e3f92301d062dcfa29128e7df5058e6e21dcb07.zip | |
Add multi-monitor support on X11.
| -rw-r--r-- | ChangeLog | 5 | ||||
| -rw-r--r-- | configure.ac | 50 | ||||
| -rw-r--r-- | etc/ChangeLog | 4 | ||||
| -rw-r--r-- | etc/NEWS | 6 | ||||
| -rw-r--r-- | lisp/ChangeLog | 5 | ||||
| -rw-r--r-- | lisp/frame.el | 61 | ||||
| -rw-r--r-- | src/ChangeLog | 25 | ||||
| -rw-r--r-- | src/Makefile.in | 10 | ||||
| -rw-r--r-- | src/xfns.c | 575 | ||||
| -rw-r--r-- | src/xterm.c | 2 | ||||
| -rw-r--r-- | src/xterm.h | 3 |
11 files changed, 743 insertions, 3 deletions
| @@ -1,3 +1,8 @@ | |||
| 1 | 2013-05-07 Jan Djärv <jan.h.d@swipnet.se> | ||
| 2 | |||
| 3 | * configure.ac (HAVE_XRANDR, HAVE_XINERAMA): Define if available. | ||
| 4 | (XRANDR_LIBS, XINERAMA_LIBS): New AC_SUBSTs. | ||
| 5 | |||
| 1 | 2013-05-06 Paul Eggert <eggert@cs.ucla.edu> | 6 | 2013-05-06 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 7 | ||
| 3 | Merge from gnulib, incorporating: | 8 | Merge from gnulib, incorporating: |
diff --git a/configure.ac b/configure.ac index 6c59dcaa7e3..e3a10275df4 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -2814,6 +2814,56 @@ if test "${HAVE_X11}" = "yes"; then | |||
| 2814 | fi | 2814 | fi |
| 2815 | AC_SUBST(LIBXSM) | 2815 | AC_SUBST(LIBXSM) |
| 2816 | 2816 | ||
| 2817 | ### Use XRandr (-lXrandr) if available | ||
| 2818 | HAVE_XRANDR=no | ||
| 2819 | if test "${HAVE_X11}" = "yes"; then | ||
| 2820 | XRANDR_REQUIRED=1.2.2 | ||
| 2821 | XRANDR_MODULES="xrandr >= $XRANDR_REQUIRED" | ||
| 2822 | PKG_CHECK_MODULES(XRANDR, $XRANDR_MODULES, HAVE_XRANDR=yes, HAVE_XRANDR=no) | ||
| 2823 | if test $HAVE_XRANDR = no; then | ||
| 2824 | # Test old way in case pkg-config doesn't have it (older machines). | ||
| 2825 | AC_CHECK_HEADER(X11/extensions/Xrandr.h, | ||
| 2826 | [AC_CHECK_LIB(Xrandr, XRRQueryExtension, HAVE_XRANDR=yes)]) | ||
| 2827 | if test $HAVE_XRANDR = yes; then | ||
| 2828 | XRANDR_LIBS=-lXrandr | ||
| 2829 | AC_SUBST(XRANDR_LIBS) | ||
| 2830 | fi | ||
| 2831 | fi | ||
| 2832 | if test $HAVE_XRANDR = yes; then | ||
| 2833 | SAVE_CFLAGS="$CFLAGS" | ||
| 2834 | SAVE_LIBS="$LIBS" | ||
| 2835 | CFLAGS="$XRANDR_CFLAGS $CFLAGS" | ||
| 2836 | LIBS="$XRANDR_LIBS $LIBS" | ||
| 2837 | AC_CHECK_FUNCS(XRRGetOutputPrimary XRRGetScreenResourcesCurrent) | ||
| 2838 | CFLAGS="$SAVE_CFLAGS" | ||
| 2839 | LIBS="$SAVE_LIBS" | ||
| 2840 | |||
| 2841 | AC_DEFINE(HAVE_XRANDR, 1, [Define to 1 if you have the XRandr extension.]) | ||
| 2842 | fi | ||
| 2843 | fi | ||
| 2844 | |||
| 2845 | ### Use Xinerama (-lXinerama) if available | ||
| 2846 | HAVE_XINERAMA=no | ||
| 2847 | if test "${HAVE_X11}" = "yes"; then | ||
| 2848 | XINERAMA_REQUIRED=1.0.2 | ||
| 2849 | XINERAMA_MODULES="xinerama >= $XINERAMA_REQUIRED" | ||
| 2850 | PKG_CHECK_MODULES(XINERAMA, $XINERAMA_MODULES, HAVE_XINERAMA=yes, | ||
| 2851 | HAVE_XINERAMA=no) | ||
| 2852 | if test $HAVE_XINERAMA = no; then | ||
| 2853 | # Test old way in case pkg-config doesn't have it (older machines). | ||
| 2854 | AC_CHECK_HEADER(X11/extensions/Xinerama.h, | ||
| 2855 | [AC_CHECK_LIB(Xinerama, XineramaQueryExtension, HAVE_XINERAMA=yes)]) | ||
| 2856 | if test $HAVE_XINERAMA = yes; then | ||
| 2857 | XINERAMA_LIBS=-lXinerama | ||
| 2858 | AC_SUBST(XINERAMA_LIBS) | ||
| 2859 | fi | ||
| 2860 | fi | ||
| 2861 | if test $HAVE_XINERAMA = yes; then | ||
| 2862 | AC_DEFINE(HAVE_XINERAMA, 1, [Define to 1 if you have the Xinerama extension.]) | ||
| 2863 | fi | ||
| 2864 | fi | ||
| 2865 | |||
| 2866 | |||
| 2817 | ### Use libxml (-lxml2) if available | 2867 | ### Use libxml (-lxml2) if available |
| 2818 | HAVE_LIBXML2=no | 2868 | HAVE_LIBXML2=no |
| 2819 | if test "${with_xml2}" != "no"; then | 2869 | if test "${with_xml2}" != "no"; then |
diff --git a/etc/ChangeLog b/etc/ChangeLog index 9cbd67c209f..4e9ba154cfe 100644 --- a/etc/ChangeLog +++ b/etc/ChangeLog | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | 2013-05-07 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> | ||
| 2 | |||
| 3 | * NEWS: Mention multi-monitor support. | ||
| 4 | |||
| 1 | 2013-05-05 Paul Eggert <eggert@cs.ucla.edu> | 5 | 2013-05-05 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 6 | ||
| 3 | `write-region-inhibit-fsync' defaults to noninteractive (Bug#14273). | 7 | `write-region-inhibit-fsync' defaults to noninteractive (Bug#14273). |
| @@ -79,6 +79,12 @@ of the buffer is visible). | |||
| 79 | 79 | ||
| 80 | ** In compiled Lisp files, the header no longer includes a timestamp. | 80 | ** In compiled Lisp files, the header no longer includes a timestamp. |
| 81 | 81 | ||
| 82 | ** Multi-monitor support has been added. | ||
| 83 | |||
| 84 | *** New functions `display-monitor-attributes-list' and | ||
| 85 | `frame-monitor-attributes' can be used to obtain information about | ||
| 86 | each physical monitor on multi-monitor setups. | ||
| 87 | |||
| 82 | 88 | ||
| 83 | * Editing Changes in Emacs 24.4 | 89 | * Editing Changes in Emacs 24.4 |
| 84 | 90 | ||
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index c4dbc803fcc..676e4286395 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,8 @@ | |||
| 1 | 2013-05-07 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> | ||
| 2 | |||
| 3 | * frame.el (display-monitor-attributes-list) | ||
| 4 | (frame-monitor-attributes): New functions. | ||
| 5 | |||
| 1 | 2013-05-06 Leo Liu <sdl.web@gmail.com> | 6 | 2013-05-06 Leo Liu <sdl.web@gmail.com> |
| 2 | 7 | ||
| 3 | * progmodes/octave.el (octave-syntax-propertize-function): Change | 8 | * progmodes/octave.el (octave-syntax-propertize-function): Change |
diff --git a/lisp/frame.el b/lisp/frame.el index 454b229d59e..94a4842fc4e 100644 --- a/lisp/frame.el +++ b/lisp/frame.el | |||
| @@ -1256,6 +1256,23 @@ bars (top, bottom, or nil)." | |||
| 1256 | (unless (memq vert '(left right nil)) | 1256 | (unless (memq vert '(left right nil)) |
| 1257 | (setq vert default-frame-scroll-bars)) | 1257 | (setq vert default-frame-scroll-bars)) |
| 1258 | (cons vert hor))) | 1258 | (cons vert hor))) |
| 1259 | |||
| 1260 | (defun frame-monitor-attributes (&optional frame) | ||
| 1261 | "Return the attributes of the physical monitor dominating FRAME. | ||
| 1262 | If FRAME is omitted, describe the currently selected frame. | ||
| 1263 | |||
| 1264 | A frame is dominated by a physical monitor when either the | ||
| 1265 | largest area of the frame resides in the monitor, or the monitor | ||
| 1266 | is the closest to the frame if the frame does not intersect any | ||
| 1267 | physical monitors. | ||
| 1268 | |||
| 1269 | See `display-monitor-attributes-list' for the list of attribute | ||
| 1270 | keys and their meanings." | ||
| 1271 | (or frame (setq frame (selected-frame))) | ||
| 1272 | (cl-loop for attributes in (display-monitor-attributes-list frame) | ||
| 1273 | for frames = (cdr (assq 'frames attributes)) | ||
| 1274 | if (memq frame frames) return attributes)) | ||
| 1275 | |||
| 1259 | 1276 | ||
| 1260 | ;;;; Frame/display capabilities. | 1277 | ;;;; Frame/display capabilities. |
| 1261 | (defun selected-terminal () | 1278 | (defun selected-terminal () |
| @@ -1476,6 +1493,50 @@ The value is one of the symbols `static-gray', `gray-scale', | |||
| 1476 | (t | 1493 | (t |
| 1477 | 'static-gray)))) | 1494 | 'static-gray)))) |
| 1478 | 1495 | ||
| 1496 | (declare-function x-display-monitor-attributes-list "xfns.c" | ||
| 1497 | (&optional terminal)) | ||
| 1498 | |||
| 1499 | (defun display-monitor-attributes-list (&optional display) | ||
| 1500 | "Return a list of physical monitor attributes on DISPLAY. | ||
| 1501 | Each element of the list represents the attributes of each | ||
| 1502 | physical monitor. The first element corresponds to the primary | ||
| 1503 | monitor. | ||
| 1504 | |||
| 1505 | Attributes for a physical monitor is represented as an alist of | ||
| 1506 | attribute keys and values as follows: | ||
| 1507 | |||
| 1508 | geometry -- Position and size in pixels in the form of | ||
| 1509 | (X Y WIDTH HEIGHT) | ||
| 1510 | workarea -- Position and size of the workarea in pixels in the | ||
| 1511 | form of (X Y WIDTH HEIGHT) | ||
| 1512 | mm-size -- Width and height in millimeters in the form of | ||
| 1513 | (WIDTH HEIGHT) | ||
| 1514 | frames -- List of frames dominated by the physical monitor | ||
| 1515 | name (*) -- Name of the physical monitor as a string | ||
| 1516 | |||
| 1517 | where X, Y, WIDTH, and HEIGHT are integers. Keys labeled | ||
| 1518 | with (*) are optional. | ||
| 1519 | |||
| 1520 | A frame is dominated by a physical monitor when either the | ||
| 1521 | largest area of the frame resides in the monitor, or the monitor | ||
| 1522 | is the closest to the frame if the frame does not intersect any | ||
| 1523 | physical monitors. Every non-tip frame (including invisible one) | ||
| 1524 | in a graphical display is dominated by exactly one physical | ||
| 1525 | monitor at a time, though it can span multiple (or no) physical | ||
| 1526 | monitors." | ||
| 1527 | (let ((frame-type (framep-on-display display))) | ||
| 1528 | (cond | ||
| 1529 | ((eq frame-type 'x) | ||
| 1530 | (x-display-monitor-attributes-list display)) | ||
| 1531 | (t | ||
| 1532 | (let ((geometry (list 0 0 (display-pixel-width display) | ||
| 1533 | (display-pixel-height display)))) | ||
| 1534 | `(((geometry . ,geometry) | ||
| 1535 | (workarea . ,geometry) | ||
| 1536 | (mm-size . (,(display-mm-width display) | ||
| 1537 | ,(display-mm-height display))) | ||
| 1538 | (frames . ,(frames-on-display-list display))))))))) | ||
| 1539 | |||
| 1479 | 1540 | ||
| 1480 | ;;;; Frame geometry values | 1541 | ;;;; Frame geometry values |
| 1481 | 1542 | ||
diff --git a/src/ChangeLog b/src/ChangeLog index 5ac0f885d8e..0d06f4e291d 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,28 @@ | |||
| 1 | 2013-05-07 YAMAMOTO Mitsuharu <mituharu@math.s.chiba-u.ac.jp> | ||
| 2 | Jan Djärv <jan.h.d@swipnet.se> | ||
| 3 | |||
| 4 | * Makefile.in (XRANDR_LIBS, XRANDR_CFLAGS, XINERAMA_LIBS) | ||
| 5 | (XINERAMA_CFLAGS): New macros. | ||
| 6 | (ALL_CFLAGS, LIBES): Use them. | ||
| 7 | |||
| 8 | * xfns.c: Include <X11/extensions/Xrandr.h> if HAVE_XRANDR, and | ||
| 9 | include <X11/extensions/Xinerama.h> if HAVE_XINERAMA. | ||
| 10 | (Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource): New variables. | ||
| 11 | (syms_of_xfns): DEFSYM them. | ||
| 12 | (struct MonitorInfo): New struct. | ||
| 13 | (x_get_net_workarea, free_monitors, x_get_monitor_for_frame) | ||
| 14 | (x_make_monitor_attribute_list, x_get_monitor_attributes_fallback) | ||
| 15 | (x_get_monitor_attributes_xrandr, x_get_monitor_attributes) | ||
| 16 | (x_get_monitor_attributes_xinerama): New functions. | ||
| 17 | (Fx_display_monitor_attributes_list): New primitive. | ||
| 18 | (syms_of_xfns): Defsubr it. | ||
| 19 | |||
| 20 | * xterm.h (x_display_info): Add Xatom_net_workarea and | ||
| 21 | Xatom_net_current_desktop. | ||
| 22 | |||
| 23 | * xterm.c (x_term_init): Initialize dpyinfo->Xatom_net_workarea | ||
| 24 | and dpyinfo->Xatom_net_current_desktop. | ||
| 25 | |||
| 1 | 2013-05-06 Eli Zaretskii <eliz@gnu.org> | 26 | 2013-05-06 Eli Zaretskii <eliz@gnu.org> |
| 2 | 27 | ||
| 3 | * xdisp.c (pos_visible_p): Use the special code for finding the | 28 | * xdisp.c (pos_visible_p): Use the special code for finding the |
diff --git a/src/Makefile.in b/src/Makefile.in index cef58c55e68..1222b5a5f98 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -232,6 +232,12 @@ IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@ | |||
| 232 | LIBXML2_LIBS = @LIBXML2_LIBS@ | 232 | LIBXML2_LIBS = @LIBXML2_LIBS@ |
| 233 | LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ | 233 | LIBXML2_CFLAGS = @LIBXML2_CFLAGS@ |
| 234 | 234 | ||
| 235 | XRANDR_LIBS = @XRANDR_LIBS@ | ||
| 236 | XRANDR_CFLAGS = @XRANDR_CFLAGS@ | ||
| 237 | |||
| 238 | XINERAMA_LIBS = @XINERAMA_LIBS@ | ||
| 239 | XINERAMA_CFLAGS = @XINERAMA_CFLAGS@ | ||
| 240 | |||
| 235 | ## widget.o if USE_X_TOOLKIT, otherwise empty. | 241 | ## widget.o if USE_X_TOOLKIT, otherwise empty. |
| 236 | WIDGET_OBJ=@WIDGET_OBJ@ | 242 | WIDGET_OBJ=@WIDGET_OBJ@ |
| 237 | 243 | ||
| @@ -315,7 +321,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ | |||
| 315 | -I$(lib) -I$(srcdir)/../lib \ | 321 | -I$(lib) -I$(srcdir)/../lib \ |
| 316 | $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \ | 322 | $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \ |
| 317 | $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ | 323 | $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ |
| 318 | $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \ | 324 | $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) \ |
| 319 | $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ | 325 | $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ |
| 320 | $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ | 326 | $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ |
| 321 | $(LIBGNUTLS_CFLAGS) \ | 327 | $(LIBGNUTLS_CFLAGS) \ |
| @@ -393,7 +399,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \ | |||
| 393 | $(LIBX_OTHER) $(LIBSOUND) \ | 399 | $(LIBX_OTHER) $(LIBSOUND) \ |
| 394 | $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \ | 400 | $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_CLOCK_GETTIME) \ |
| 395 | $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ | 401 | $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ |
| 396 | $(LIB_EXECINFO) \ | 402 | $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) \ |
| 397 | $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ | 403 | $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ |
| 398 | $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ | 404 | $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ |
| 399 | $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ | 405 | $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ |
diff --git a/src/xfns.c b/src/xfns.c index f4c24cb09a0..d3e3479be2d 100644 --- a/src/xfns.c +++ b/src/xfns.c | |||
| @@ -59,6 +59,13 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 59 | 59 | ||
| 60 | #include "xsettings.h" | 60 | #include "xsettings.h" |
| 61 | 61 | ||
| 62 | #ifdef HAVE_XRANDR | ||
| 63 | #include <X11/extensions/Xrandr.h> | ||
| 64 | #endif | ||
| 65 | #ifdef HAVE_XINERAMA | ||
| 66 | #include <X11/extensions/Xinerama.h> | ||
| 67 | #endif | ||
| 68 | |||
| 62 | #ifdef USE_GTK | 69 | #ifdef USE_GTK |
| 63 | #include "gtkutil.h" | 70 | #include "gtkutil.h" |
| 64 | #endif | 71 | #endif |
| @@ -126,6 +133,7 @@ extern LWLIB_ID widget_id_tick; | |||
| 126 | static Lisp_Object Qsuppress_icon; | 133 | static Lisp_Object Qsuppress_icon; |
| 127 | static Lisp_Object Qundefined_color; | 134 | static Lisp_Object Qundefined_color; |
| 128 | static Lisp_Object Qcompound_text, Qcancel_timer; | 135 | static Lisp_Object Qcompound_text, Qcancel_timer; |
| 136 | static Lisp_Object Qgeometry, Qworkarea, Qmm_size, Qframes, Qsource; | ||
| 129 | Lisp_Object Qfont_param; | 137 | Lisp_Object Qfont_param; |
| 130 | 138 | ||
| 131 | #ifdef GLYPH_DEBUG | 139 | #ifdef GLYPH_DEBUG |
| @@ -3791,6 +3799,567 @@ If omitted or nil, that stands for the selected frame's display. */) | |||
| 3791 | else | 3799 | else |
| 3792 | return Qnil; | 3800 | return Qnil; |
| 3793 | } | 3801 | } |
| 3802 | |||
| 3803 | /* Store the geometry of the workarea on display DPYINFO into *RECT. | ||
| 3804 | Return false if and only if the workarea information cannot be | ||
| 3805 | obtained via the _NET_WORKAREA root window property. */ | ||
| 3806 | |||
| 3807 | static bool | ||
| 3808 | x_get_net_workarea (struct x_display_info *dpyinfo, XRectangle *rect) | ||
| 3809 | { | ||
| 3810 | Display *dpy = dpyinfo->display; | ||
| 3811 | long offset, max_len; | ||
| 3812 | Atom target_type, actual_type; | ||
| 3813 | unsigned long actual_size, bytes_remaining; | ||
| 3814 | int rc, actual_format; | ||
| 3815 | unsigned char *tmp_data = NULL; | ||
| 3816 | bool result = false; | ||
| 3817 | |||
| 3818 | x_catch_errors (dpy); | ||
| 3819 | offset = 0; | ||
| 3820 | max_len = 1; | ||
| 3821 | target_type = XA_CARDINAL; | ||
| 3822 | rc = XGetWindowProperty (dpy, dpyinfo->root_window, | ||
| 3823 | dpyinfo->Xatom_net_current_desktop, | ||
| 3824 | offset, max_len, False, target_type, | ||
| 3825 | &actual_type, &actual_format, &actual_size, | ||
| 3826 | &bytes_remaining, &tmp_data); | ||
| 3827 | if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy) | ||
| 3828 | && actual_format == 32 && actual_size == max_len) | ||
| 3829 | { | ||
| 3830 | long current_desktop = ((long *) tmp_data)[0]; | ||
| 3831 | |||
| 3832 | XFree (tmp_data); | ||
| 3833 | tmp_data = NULL; | ||
| 3834 | |||
| 3835 | offset = 4 * current_desktop; | ||
| 3836 | max_len = 4; | ||
| 3837 | rc = XGetWindowProperty (dpy, dpyinfo->root_window, | ||
| 3838 | dpyinfo->Xatom_net_workarea, | ||
| 3839 | offset, max_len, False, target_type, | ||
| 3840 | &actual_type, &actual_format, &actual_size, | ||
| 3841 | &bytes_remaining, &tmp_data); | ||
| 3842 | if (rc == Success && actual_type == target_type && !x_had_errors_p (dpy) | ||
| 3843 | && actual_format == 32 && actual_size == max_len) | ||
| 3844 | { | ||
| 3845 | long *values = (long *) tmp_data; | ||
| 3846 | |||
| 3847 | rect->x = values[0]; | ||
| 3848 | rect->y = values[1]; | ||
| 3849 | rect->width = values[2]; | ||
| 3850 | rect->height = values[3]; | ||
| 3851 | |||
| 3852 | XFree (tmp_data); | ||
| 3853 | tmp_data = NULL; | ||
| 3854 | |||
| 3855 | result = true; | ||
| 3856 | } | ||
| 3857 | } | ||
| 3858 | if (tmp_data) | ||
| 3859 | XFree (tmp_data); | ||
| 3860 | x_uncatch_errors (); | ||
| 3861 | |||
| 3862 | return result; | ||
| 3863 | } | ||
| 3864 | |||
| 3865 | struct MonitorInfo { | ||
| 3866 | XRectangle geom, work; | ||
| 3867 | int mm_width, mm_height; | ||
| 3868 | char *name; | ||
| 3869 | }; | ||
| 3870 | |||
| 3871 | static void | ||
| 3872 | free_monitors (struct MonitorInfo *monitors, int n_monitors) | ||
| 3873 | { | ||
| 3874 | int i; | ||
| 3875 | for (i = 0; i < n_monitors; ++i) | ||
| 3876 | xfree (monitors[i].name); | ||
| 3877 | xfree (monitors); | ||
| 3878 | } | ||
| 3879 | |||
| 3880 | |||
| 3881 | /* Return monitor number where F is "most" or closest to. */ | ||
| 3882 | static int | ||
| 3883 | x_get_monitor_for_frame (struct frame *f, | ||
| 3884 | struct MonitorInfo *monitors, | ||
| 3885 | int n_monitors) | ||
| 3886 | { | ||
| 3887 | XRectangle frect; | ||
| 3888 | int area = 0, dist = -1; | ||
| 3889 | int best_area = -1, best_dist = -1; | ||
| 3890 | int i; | ||
| 3891 | |||
| 3892 | if (n_monitors == 1) return 0; | ||
| 3893 | frect.x = f->left_pos; | ||
| 3894 | frect.y = f->top_pos; | ||
| 3895 | frect.width = FRAME_PIXEL_WIDTH (f); | ||
| 3896 | frect.height = FRAME_PIXEL_HEIGHT (f); | ||
| 3897 | |||
| 3898 | for (i = 0; i < n_monitors; ++i) | ||
| 3899 | { | ||
| 3900 | struct MonitorInfo *mi = &monitors[i]; | ||
| 3901 | XRectangle res; | ||
| 3902 | int a = 0; | ||
| 3903 | |||
| 3904 | if (mi->geom.width == 0) continue; | ||
| 3905 | |||
| 3906 | if (x_intersect_rectangles (&mi->geom, &frect, &res)) | ||
| 3907 | { | ||
| 3908 | a = res.width * res.height; | ||
| 3909 | if (a > area) { | ||
| 3910 | area = a; | ||
| 3911 | best_area = i; | ||
| 3912 | } | ||
| 3913 | } | ||
| 3914 | |||
| 3915 | if (a == 0 && area == 0) | ||
| 3916 | { | ||
| 3917 | int dx, dy, d; | ||
| 3918 | if (frect.x + frect.width < mi->geom.x) | ||
| 3919 | dx = mi->geom.x - frect.x + frect.width; | ||
| 3920 | else if (frect.x > mi->geom.x + mi->geom.width) | ||
| 3921 | dx = frect.x - mi->geom.x + mi->geom.width; | ||
| 3922 | else | ||
| 3923 | dx = 0; | ||
| 3924 | if (frect.y + frect.height < mi->geom.y) | ||
| 3925 | dy = mi->geom.y - frect.y + frect.height; | ||
| 3926 | else if (frect.y > mi->geom.y + mi->geom.height) | ||
| 3927 | dy = frect.y - mi->geom.y + mi->geom.height; | ||
| 3928 | else | ||
| 3929 | dy = 0; | ||
| 3930 | |||
| 3931 | d = dx*dx + dy*dy; | ||
| 3932 | if (dist == -1 || dist > d) | ||
| 3933 | { | ||
| 3934 | dist = d; | ||
| 3935 | best_dist = i; | ||
| 3936 | } | ||
| 3937 | } | ||
| 3938 | } | ||
| 3939 | |||
| 3940 | return best_area != -1 ? best_area : (best_dist != -1 ? best_dist : 0); | ||
| 3941 | } | ||
| 3942 | |||
| 3943 | static Lisp_Object | ||
| 3944 | x_make_monitor_attribute_list (struct MonitorInfo *monitors, | ||
| 3945 | int n_monitors, | ||
| 3946 | int primary_monitor, | ||
| 3947 | struct x_display_info *dpyinfo, | ||
| 3948 | const char *source) | ||
| 3949 | { | ||
| 3950 | Lisp_Object monitor_frames = Fmake_vector (make_number (n_monitors), Qnil); | ||
| 3951 | Lisp_Object frame, rest, attributes_list = Qnil; | ||
| 3952 | Lisp_Object primary_monitor_attributes = Qnil; | ||
| 3953 | int i; | ||
| 3954 | |||
| 3955 | FOR_EACH_FRAME (rest, frame) | ||
| 3956 | { | ||
| 3957 | struct frame *f = XFRAME (frame); | ||
| 3958 | |||
| 3959 | if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo | ||
| 3960 | && !EQ (frame, tip_frame)) | ||
| 3961 | { | ||
| 3962 | i = x_get_monitor_for_frame (f, monitors, n_monitors); | ||
| 3963 | ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i))); | ||
| 3964 | } | ||
| 3965 | } | ||
| 3966 | |||
| 3967 | for (i = 0; i < n_monitors; ++i) | ||
| 3968 | { | ||
| 3969 | Lisp_Object geometry, workarea, attributes = Qnil; | ||
| 3970 | struct MonitorInfo *mi = &monitors[i]; | ||
| 3971 | |||
| 3972 | if (mi->geom.width == 0) continue; | ||
| 3973 | |||
| 3974 | workarea = list4i (mi->work.x, mi->work.y, | ||
| 3975 | mi->work.width, mi->work.height); | ||
| 3976 | geometry = list4i (mi->geom.x, mi->geom.y, | ||
| 3977 | mi->geom.width, mi->geom.height); | ||
| 3978 | attributes = Fcons (Fcons (Qsource, | ||
| 3979 | make_string (source, strlen (source))), | ||
| 3980 | attributes); | ||
| 3981 | attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)), | ||
| 3982 | attributes); | ||
| 3983 | attributes = Fcons (Fcons (Qmm_size, | ||
| 3984 | list2i (mi->mm_width, mi->mm_height)), | ||
| 3985 | attributes); | ||
| 3986 | attributes = Fcons (Fcons (Qworkarea, workarea), attributes); | ||
| 3987 | attributes = Fcons (Fcons (Qgeometry, geometry), attributes); | ||
| 3988 | if (mi->name) | ||
| 3989 | attributes = Fcons (Fcons (Qname, make_string (mi->name, | ||
| 3990 | strlen (mi->name))), | ||
| 3991 | attributes); | ||
| 3992 | |||
| 3993 | if (i == primary_monitor) | ||
| 3994 | primary_monitor_attributes = attributes; | ||
| 3995 | else | ||
| 3996 | attributes_list = Fcons (attributes, attributes_list); | ||
| 3997 | } | ||
| 3998 | |||
| 3999 | if (!NILP (primary_monitor_attributes)) | ||
| 4000 | attributes_list = Fcons (primary_monitor_attributes, attributes_list); | ||
| 4001 | return attributes_list; | ||
| 4002 | } | ||
| 4003 | |||
| 4004 | static Lisp_Object | ||
| 4005 | x_get_monitor_attributes_fallback (struct x_display_info *dpyinfo) | ||
| 4006 | { | ||
| 4007 | struct MonitorInfo monitor; | ||
| 4008 | int width_mm, height_mm; | ||
| 4009 | XRectangle workarea_r; | ||
| 4010 | |||
| 4011 | /* Fallback: treat (possibly) multiple physical monitors as if they | ||
| 4012 | formed a single monitor as a whole. This should provide a | ||
| 4013 | consistent result at least on single monitor environments. */ | ||
| 4014 | monitor.geom.x = monitor.geom.y = 0; | ||
| 4015 | monitor.geom.width = x_display_pixel_width (dpyinfo); | ||
| 4016 | monitor.geom.height = x_display_pixel_height (dpyinfo); | ||
| 4017 | monitor.mm_width = WidthMMOfScreen (dpyinfo->screen); | ||
| 4018 | monitor.mm_height = HeightMMOfScreen (dpyinfo->screen); | ||
| 4019 | monitor.name = xstrdup ("combined screen"); | ||
| 4020 | |||
| 4021 | if (x_get_net_workarea (dpyinfo, &workarea_r)) | ||
| 4022 | monitor.work = workarea_r; | ||
| 4023 | else | ||
| 4024 | monitor.work = monitor.geom; | ||
| 4025 | return x_make_monitor_attribute_list (&monitor, 1, 0, dpyinfo, "fallback"); | ||
| 4026 | } | ||
| 4027 | |||
| 4028 | |||
| 4029 | #ifdef HAVE_XINERAMA | ||
| 4030 | static Lisp_Object | ||
| 4031 | x_get_monitor_attributes_xinerama (struct x_display_info *dpyinfo) | ||
| 4032 | { | ||
| 4033 | int n_monitors, i; | ||
| 4034 | Lisp_Object attributes_list = Qnil; | ||
| 4035 | Display *dpy = dpyinfo->display; | ||
| 4036 | XineramaScreenInfo *info = XineramaQueryScreens (dpy, &n_monitors); | ||
| 4037 | struct MonitorInfo *monitors; | ||
| 4038 | float mm_width_per_pixel, mm_height_per_pixel; | ||
| 4039 | |||
| 4040 | if (! info || n_monitors == 0) | ||
| 4041 | { | ||
| 4042 | if (info) | ||
| 4043 | XFree (info); | ||
| 4044 | return attributes_list; | ||
| 4045 | } | ||
| 4046 | |||
| 4047 | mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen) | ||
| 4048 | / x_display_pixel_width (dpyinfo)); | ||
| 4049 | mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen) | ||
| 4050 | / x_display_pixel_height (dpyinfo)); | ||
| 4051 | monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors)); | ||
| 4052 | for (i = 0; i < n_monitors; ++i) | ||
| 4053 | { | ||
| 4054 | struct MonitorInfo *mi = &monitors[i]; | ||
| 4055 | XRectangle workarea_r; | ||
| 4056 | |||
| 4057 | mi->geom.x = info[i].x_org; | ||
| 4058 | mi->geom.y = info[i].y_org; | ||
| 4059 | mi->geom.width = info[i].width; | ||
| 4060 | mi->geom.height = info[i].height; | ||
| 4061 | mi->mm_width = mi->geom.width * mm_width_per_pixel + 0.5; | ||
| 4062 | mi->mm_height = mi->geom.height * mm_height_per_pixel + 0.5; | ||
| 4063 | mi->name = 0; | ||
| 4064 | |||
| 4065 | /* Xinerama usually have primary monitor first, just use that. */ | ||
| 4066 | if (i == 0 && x_get_net_workarea (dpyinfo, &workarea_r)) | ||
| 4067 | { | ||
| 4068 | mi->work = workarea_r; | ||
| 4069 | if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work)) | ||
| 4070 | mi->work = mi->geom; | ||
| 4071 | } | ||
| 4072 | else | ||
| 4073 | mi->work = mi->geom; | ||
| 4074 | } | ||
| 4075 | XFree (info); | ||
| 4076 | |||
| 4077 | attributes_list = x_make_monitor_attribute_list (monitors, | ||
| 4078 | n_monitors, | ||
| 4079 | 0, | ||
| 4080 | dpyinfo, | ||
| 4081 | "Xinerama"); | ||
| 4082 | free_monitors (monitors, n_monitors); | ||
| 4083 | return attributes_list; | ||
| 4084 | } | ||
| 4085 | #endif /* HAVE_XINERAMA */ | ||
| 4086 | |||
| 4087 | |||
| 4088 | #ifdef HAVE_XRANDR | ||
| 4089 | static Lisp_Object | ||
| 4090 | x_get_monitor_attributes_xrandr (struct x_display_info *dpyinfo) | ||
| 4091 | { | ||
| 4092 | Lisp_Object attributes_list = Qnil; | ||
| 4093 | XRRScreenResources *resources; | ||
| 4094 | Display *dpy = dpyinfo->display; | ||
| 4095 | int i, n_monitors, primary = -1; | ||
| 4096 | RROutput pxid = None; | ||
| 4097 | struct MonitorInfo *monitors; | ||
| 4098 | |||
| 4099 | #ifdef HAVE_XRRGETSCREENRESOURCESCURRENT | ||
| 4100 | resources = XRRGetScreenResourcesCurrent (dpy, dpyinfo->root_window); | ||
| 4101 | #else | ||
| 4102 | resources = XRRGetScreenResources (dpy, dpyinfo->root_window); | ||
| 4103 | #endif | ||
| 4104 | if (! resources || resources->noutput == 0) | ||
| 4105 | { | ||
| 4106 | if (resources) | ||
| 4107 | XRRFreeScreenResources (resources); | ||
| 4108 | return Qnil; | ||
| 4109 | } | ||
| 4110 | n_monitors = resources->noutput; | ||
| 4111 | monitors = (struct MonitorInfo *) xzalloc (n_monitors * sizeof (*monitors)); | ||
| 4112 | |||
| 4113 | #ifdef HAVE_XRRGETOUTPUTPRIMARY | ||
| 4114 | pxid = XRRGetOutputPrimary (dpy, dpyinfo->root_window); | ||
| 4115 | #endif | ||
| 4116 | |||
| 4117 | for (i = 0; i < n_monitors; ++i) | ||
| 4118 | { | ||
| 4119 | XRROutputInfo *info = XRRGetOutputInfo (dpy, resources, | ||
| 4120 | resources->outputs[i]); | ||
| 4121 | Connection conn = info ? info->connection : RR_Disconnected; | ||
| 4122 | RRCrtc id = info ? info->crtc : None; | ||
| 4123 | |||
| 4124 | if (strcmp (info->name, "default") == 0) | ||
| 4125 | { | ||
| 4126 | /* Non XRandr 1.2 driver, does not give useful data. */ | ||
| 4127 | XRRFreeOutputInfo (info); | ||
| 4128 | XRRFreeScreenResources (resources); | ||
| 4129 | free_monitors (monitors, n_monitors); | ||
| 4130 | return Qnil; | ||
| 4131 | } | ||
| 4132 | |||
| 4133 | if (conn != RR_Disconnected && id != None) | ||
| 4134 | { | ||
| 4135 | XRRCrtcInfo *crtc = XRRGetCrtcInfo (dpy, resources, id); | ||
| 4136 | struct MonitorInfo *mi = &monitors[i]; | ||
| 4137 | XRectangle workarea_r; | ||
| 4138 | |||
| 4139 | if (! crtc) | ||
| 4140 | { | ||
| 4141 | XRRFreeOutputInfo (info); | ||
| 4142 | continue; | ||
| 4143 | } | ||
| 4144 | |||
| 4145 | mi->geom.x = crtc->x; | ||
| 4146 | mi->geom.y = crtc->y; | ||
| 4147 | mi->geom.width = crtc->width; | ||
| 4148 | mi->geom.height = crtc->height; | ||
| 4149 | mi->mm_width = info->mm_width; | ||
| 4150 | mi->mm_height = info->mm_height; | ||
| 4151 | mi->name = xstrdup (info->name); | ||
| 4152 | |||
| 4153 | if (pxid != None && pxid == resources->outputs[i]) | ||
| 4154 | primary = i; | ||
| 4155 | else if (primary == -1 && strcmp (info->name, "LVDS") == 0) | ||
| 4156 | primary = i; | ||
| 4157 | |||
| 4158 | if (i == primary && x_get_net_workarea (dpyinfo, &workarea_r)) | ||
| 4159 | { | ||
| 4160 | mi->work= workarea_r; | ||
| 4161 | if (! x_intersect_rectangles (&mi->geom, &mi->work, &mi->work)) | ||
| 4162 | mi->work = mi->geom; | ||
| 4163 | } | ||
| 4164 | else | ||
| 4165 | mi->work = mi->geom; | ||
| 4166 | |||
| 4167 | XRRFreeCrtcInfo (crtc); | ||
| 4168 | } | ||
| 4169 | XRRFreeOutputInfo (info); | ||
| 4170 | } | ||
| 4171 | XRRFreeScreenResources (resources); | ||
| 4172 | |||
| 4173 | attributes_list = x_make_monitor_attribute_list (monitors, | ||
| 4174 | n_monitors, | ||
| 4175 | primary, | ||
| 4176 | dpyinfo, | ||
| 4177 | "XRandr"); | ||
| 4178 | free_monitors (monitors, n_monitors); | ||
| 4179 | return attributes_list; | ||
| 4180 | } | ||
| 4181 | #endif /* HAVE_XRANDR */ | ||
| 4182 | |||
| 4183 | static Lisp_Object | ||
| 4184 | x_get_monitor_attributes (struct x_display_info *dpyinfo) | ||
| 4185 | { | ||
| 4186 | Lisp_Object attributes_list = Qnil; | ||
| 4187 | Display *dpy = dpyinfo->display; | ||
| 4188 | |||
| 4189 | #ifdef HAVE_XRANDR | ||
| 4190 | int xrr_event_base, xrr_error_base; | ||
| 4191 | bool xrr_ok = false; | ||
| 4192 | xrr_ok = XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base); | ||
| 4193 | if (xrr_ok) | ||
| 4194 | { | ||
| 4195 | int xrr_major, xrr_minor; | ||
| 4196 | XRRQueryVersion (dpy, &xrr_major, &xrr_minor); | ||
| 4197 | xrr_ok = (xrr_major == 1 && xrr_minor >= 2) || xrr_major > 1; | ||
| 4198 | } | ||
| 4199 | |||
| 4200 | if (xrr_ok) | ||
| 4201 | attributes_list = x_get_monitor_attributes_xrandr (dpyinfo); | ||
| 4202 | #endif /* HAVE_XRANDR */ | ||
| 4203 | |||
| 4204 | #ifdef HAVE_XINERAMA | ||
| 4205 | if (NILP (attributes_list)) | ||
| 4206 | { | ||
| 4207 | int xin_event_base, xin_error_base; | ||
| 4208 | bool xin_ok = false; | ||
| 4209 | xin_ok = XineramaQueryExtension (dpy, &xin_event_base, &xin_error_base); | ||
| 4210 | if (xin_ok && XineramaIsActive (dpy)) | ||
| 4211 | attributes_list = x_get_monitor_attributes_xinerama (dpyinfo); | ||
| 4212 | } | ||
| 4213 | #endif /* HAVE_XINERAMA */ | ||
| 4214 | |||
| 4215 | if (NILP (attributes_list)) | ||
| 4216 | attributes_list = x_get_monitor_attributes_fallback (dpyinfo); | ||
| 4217 | |||
| 4218 | return attributes_list; | ||
| 4219 | } | ||
| 4220 | |||
| 4221 | DEFUN ("x-display-monitor-attributes-list", Fx_display_monitor_attributes_list, | ||
| 4222 | Sx_display_monitor_attributes_list, | ||
| 4223 | 0, 1, 0, | ||
| 4224 | doc: /* Return a list of physical monitor attributes on the X display TERMINAL. | ||
| 4225 | |||
| 4226 | The optional argument TERMINAL specifies which display to ask about. | ||
| 4227 | TERMINAL should be a terminal object, a frame or a display name (a string). | ||
| 4228 | If omitted or nil, that stands for the selected frame's display. | ||
| 4229 | |||
| 4230 | In addition to the standard attribute keys listed in | ||
| 4231 | `display-monitor-attributes-list', the following keys are contained in | ||
| 4232 | the attributes: | ||
| 4233 | |||
| 4234 | source -- String describing the source from which multi-monitor | ||
| 4235 | information is obtained, one of \"Gdk\", \"XRandr\", | ||
| 4236 | \"Xinerama\", or \"fallback\" | ||
| 4237 | |||
| 4238 | Internal use only, use `display-monitor-attributes-list' instead. */) | ||
| 4239 | (Lisp_Object terminal) | ||
| 4240 | { | ||
| 4241 | struct x_display_info *dpyinfo = check_x_display_info (terminal); | ||
| 4242 | Lisp_Object attributes_list = Qnil; | ||
| 4243 | |||
| 4244 | #ifdef USE_GTK | ||
| 4245 | float mm_width_per_pixel, mm_height_per_pixel; | ||
| 4246 | GdkDisplay *gdpy; | ||
| 4247 | GdkScreen *gscreen; | ||
| 4248 | gint primary_monitor = 0, n_monitors, i; | ||
| 4249 | Lisp_Object primary_monitor_attributes = Qnil; | ||
| 4250 | Lisp_Object monitor_frames, rest, frame; | ||
| 4251 | static const char *source = "Gdk"; | ||
| 4252 | |||
| 4253 | block_input (); | ||
| 4254 | mm_width_per_pixel = ((float) WidthMMOfScreen (dpyinfo->screen) | ||
| 4255 | / x_display_pixel_width (dpyinfo)); | ||
| 4256 | mm_height_per_pixel = ((float) HeightMMOfScreen (dpyinfo->screen) | ||
| 4257 | / x_display_pixel_height (dpyinfo)); | ||
| 4258 | gdpy = gdk_x11_lookup_xdisplay (dpyinfo->display); | ||
| 4259 | gscreen = gdk_display_get_default_screen (gdpy); | ||
| 4260 | #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 20 | ||
| 4261 | primary_monitor = gdk_screen_get_primary_monitor (gscreen); | ||
| 4262 | #endif | ||
| 4263 | n_monitors = gdk_screen_get_n_monitors (gscreen); | ||
| 4264 | monitor_frames = Fmake_vector (make_number (n_monitors), Qnil); | ||
| 4265 | FOR_EACH_FRAME (rest, frame) | ||
| 4266 | { | ||
| 4267 | struct frame *f = XFRAME (frame); | ||
| 4268 | |||
| 4269 | if (FRAME_X_P (f) && FRAME_X_DISPLAY_INFO (f) == dpyinfo | ||
| 4270 | && !EQ (frame, tip_frame)) | ||
| 4271 | { | ||
| 4272 | GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_WIDGET (f)); | ||
| 4273 | |||
| 4274 | i = gdk_screen_get_monitor_at_window (gscreen, gwin); | ||
| 4275 | ASET (monitor_frames, i, Fcons (frame, AREF (monitor_frames, i))); | ||
| 4276 | } | ||
| 4277 | } | ||
| 4278 | |||
| 4279 | i = n_monitors; | ||
| 4280 | while (i-- > 0) | ||
| 4281 | { | ||
| 4282 | Lisp_Object geometry, workarea, attributes = Qnil; | ||
| 4283 | gint width_mm = -1, height_mm = -1; | ||
| 4284 | GdkRectangle rec; | ||
| 4285 | |||
| 4286 | attributes = Fcons (Fcons (Qsource, | ||
| 4287 | make_string (source, strlen (source))), | ||
| 4288 | attributes); | ||
| 4289 | attributes = Fcons (Fcons (Qframes, AREF (monitor_frames, i)), | ||
| 4290 | attributes); | ||
| 4291 | |||
| 4292 | gdk_screen_get_monitor_geometry (gscreen, i, &rec); | ||
| 4293 | geometry = list4i (rec.x, rec.y, rec.width, rec.height); | ||
| 4294 | |||
| 4295 | #if GTK_MAJOR_VERSION > 2 || GTK_MINOR_VERSION >= 14 | ||
| 4296 | width_mm = gdk_screen_get_monitor_width_mm (gscreen, i); | ||
| 4297 | height_mm = gdk_screen_get_monitor_height_mm (gscreen, i); | ||
| 4298 | #endif | ||
| 4299 | if (width_mm < 0) | ||
| 4300 | width_mm = rec.width * mm_width_per_pixel + 0.5; | ||
| 4301 | if (height_mm < 0) | ||
| 4302 | height_mm = rec.height * mm_height_per_pixel + 0.5; | ||
| 4303 | attributes = Fcons (Fcons (Qmm_size, | ||
| 4304 | list2i (width_mm, height_mm)), | ||
| 4305 | attributes); | ||
| 4306 | |||
| 4307 | #if GTK_MAJOR_VERSION > 3 || (GTK_MAJOR_VERSION == 3 && GTK_MINOR_VERSION >= 4) | ||
| 4308 | gdk_screen_get_monitor_workarea (gscreen, i, &rec); | ||
| 4309 | workarea = list4i (rec.x, rec.y, rec.width, rec.height); | ||
| 4310 | #else | ||
| 4311 | /* Emulate the behavior of GTK+ 3.4. */ | ||
| 4312 | { | ||
| 4313 | XRectangle workarea_r; | ||
| 4314 | |||
| 4315 | workarea = Qnil; | ||
| 4316 | if (i == primary_monitor && x_get_net_workarea (dpyinfo, &workarea_r)) | ||
| 4317 | { | ||
| 4318 | GdkRectangle work; | ||
| 4319 | |||
| 4320 | work.x = workarea_r.x; | ||
| 4321 | work.y = workarea_r.y; | ||
| 4322 | work.width = workarea_r.width; | ||
| 4323 | work.height = workarea_r.height; | ||
| 4324 | if (gdk_rectangle_intersect (&rec, &work, &work)) | ||
| 4325 | workarea = list4i (work.x, work.y, work.width, work.height); | ||
| 4326 | } | ||
| 4327 | if (NILP (workarea)) | ||
| 4328 | workarea = geometry; | ||
| 4329 | } | ||
| 4330 | #endif | ||
| 4331 | attributes = Fcons (Fcons (Qworkarea, workarea), attributes); | ||
| 4332 | |||
| 4333 | attributes = Fcons (Fcons (Qgeometry, geometry), attributes); | ||
| 4334 | #if GTK_MAJOR_VERSION > 2 || (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION >= 14) | ||
| 4335 | { | ||
| 4336 | char *name = gdk_screen_get_monitor_plug_name (gscreen, i); | ||
| 4337 | if (name) | ||
| 4338 | attributes = Fcons (Fcons (Qname, make_string (name, strlen (name))), | ||
| 4339 | attributes); | ||
| 4340 | } | ||
| 4341 | #endif | ||
| 4342 | |||
| 4343 | if (i == primary_monitor) | ||
| 4344 | primary_monitor_attributes = attributes; | ||
| 4345 | else | ||
| 4346 | attributes_list = Fcons (attributes, attributes_list); | ||
| 4347 | } | ||
| 4348 | |||
| 4349 | if (!NILP (primary_monitor_attributes)) | ||
| 4350 | attributes_list = Fcons (primary_monitor_attributes, attributes_list); | ||
| 4351 | unblock_input (); | ||
| 4352 | #else /* not USE_GTK */ | ||
| 4353 | |||
| 4354 | block_input (); | ||
| 4355 | attributes_list = x_get_monitor_attributes (dpyinfo); | ||
| 4356 | unblock_input (); | ||
| 4357 | |||
| 4358 | #endif /* not USE_GTK */ | ||
| 4359 | |||
| 4360 | return attributes_list; | ||
| 4361 | } | ||
| 4362 | |||
| 3794 | 4363 | ||
| 3795 | int | 4364 | int |
| 3796 | x_pixel_width (register struct frame *f) | 4365 | x_pixel_width (register struct frame *f) |
| @@ -5701,6 +6270,11 @@ syms_of_xfns (void) | |||
| 5701 | DEFSYM (Qundefined_color, "undefined-color"); | 6270 | DEFSYM (Qundefined_color, "undefined-color"); |
| 5702 | DEFSYM (Qcompound_text, "compound-text"); | 6271 | DEFSYM (Qcompound_text, "compound-text"); |
| 5703 | DEFSYM (Qcancel_timer, "cancel-timer"); | 6272 | DEFSYM (Qcancel_timer, "cancel-timer"); |
| 6273 | DEFSYM (Qgeometry, "geometry"); | ||
| 6274 | DEFSYM (Qworkarea, "workarea"); | ||
| 6275 | DEFSYM (Qmm_size, "mm-size"); | ||
| 6276 | DEFSYM (Qframes, "frames"); | ||
| 6277 | DEFSYM (Qsource, "source"); | ||
| 5704 | DEFSYM (Qfont_param, "font-parameter"); | 6278 | DEFSYM (Qfont_param, "font-parameter"); |
| 5705 | /* This is the end of symbol initialization. */ | 6279 | /* This is the end of symbol initialization. */ |
| 5706 | 6280 | ||
| @@ -5864,6 +6438,7 @@ When using Gtk+ tooltips, the tooltip face is not used. */); | |||
| 5864 | defsubr (&Sx_display_visual_class); | 6438 | defsubr (&Sx_display_visual_class); |
| 5865 | defsubr (&Sx_display_backing_store); | 6439 | defsubr (&Sx_display_backing_store); |
| 5866 | defsubr (&Sx_display_save_under); | 6440 | defsubr (&Sx_display_save_under); |
| 6441 | defsubr (&Sx_display_monitor_attributes_list); | ||
| 5867 | defsubr (&Sx_wm_set_size_hint); | 6442 | defsubr (&Sx_wm_set_size_hint); |
| 5868 | defsubr (&Sx_create_frame); | 6443 | defsubr (&Sx_create_frame); |
| 5869 | defsubr (&Sx_open_connection); | 6444 | defsubr (&Sx_open_connection); |
diff --git a/src/xterm.c b/src/xterm.c index e4a681031ef..93473986ca5 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -10251,6 +10251,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) | |||
| 10251 | { "_NET_WM_WINDOW_OPACITY", &dpyinfo->Xatom_net_wm_window_opacity }, | 10251 | { "_NET_WM_WINDOW_OPACITY", &dpyinfo->Xatom_net_wm_window_opacity }, |
| 10252 | { "_NET_ACTIVE_WINDOW", &dpyinfo->Xatom_net_active_window }, | 10252 | { "_NET_ACTIVE_WINDOW", &dpyinfo->Xatom_net_active_window }, |
| 10253 | { "_NET_FRAME_EXTENTS", &dpyinfo->Xatom_net_frame_extents }, | 10253 | { "_NET_FRAME_EXTENTS", &dpyinfo->Xatom_net_frame_extents }, |
| 10254 | { "_NET_CURRENT_DESKTOP", &dpyinfo->Xatom_net_current_desktop }, | ||
| 10255 | { "_NET_WORKAREA", &dpyinfo->Xatom_net_workarea }, | ||
| 10254 | /* Session management */ | 10256 | /* Session management */ |
| 10255 | { "SM_CLIENT_ID", &dpyinfo->Xatom_SM_CLIENT_ID }, | 10257 | { "SM_CLIENT_ID", &dpyinfo->Xatom_SM_CLIENT_ID }, |
| 10256 | { "_XSETTINGS_SETTINGS", &dpyinfo->Xatom_xsettings_prop }, | 10258 | { "_XSETTINGS_SETTINGS", &dpyinfo->Xatom_xsettings_prop }, |
diff --git a/src/xterm.h b/src/xterm.h index 16effc5c9ea..dc060fbbcff 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -346,7 +346,8 @@ struct x_display_info | |||
| 346 | Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen, | 346 | Atom Xatom_net_wm_state, Xatom_net_wm_state_fullscreen, |
| 347 | Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert, | 347 | Xatom_net_wm_state_maximized_horz, Xatom_net_wm_state_maximized_vert, |
| 348 | Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden, | 348 | Xatom_net_wm_state_sticky, Xatom_net_wm_state_hidden, |
| 349 | Xatom_net_frame_extents; | 349 | Xatom_net_frame_extents, |
| 350 | Xatom_net_current_desktop, Xatom_net_workarea; | ||
| 350 | 351 | ||
| 351 | /* XSettings atoms and windows. */ | 352 | /* XSettings atoms and windows. */ |
| 352 | Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr; | 353 | Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr; |