[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: x-display-pixel-width/height inconsistency
From: |
YAMAMOTO Mitsuharu |
Subject: |
Re: x-display-pixel-width/height inconsistency |
Date: |
Sat, 27 Apr 2013 14:13:46 +0900 |
User-agent: |
Wanderlust/2.14.0 (Africa) SEMI/1.14.6 (Maruoka) FLIM/1.14.8 (Shijō) APEL/10.6 Emacs/22.3 (sparc-sun-solaris2.8) MULE/5.0 (SAKAKI) |
>>>>> On Sun, 24 Mar 2013 13:36:03 +0900, YAMAMOTO Mitsuharu <address@hidden>
>>>>> 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
address@hidden
=== 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;
+ }
+
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;
- Re: x-display-pixel-width/height inconsistency,
YAMAMOTO Mitsuharu <=
Re: x-display-pixel-width/height inconsistency, YAMAMOTO Mitsuharu, 2013/04/27