From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: YAMAMOTO Mitsuharu Newsgroups: gmane.emacs.devel Subject: Re: x-display-pixel-width/height inconsistency Date: Sat, 27 Apr 2013 14:13:46 +0900 Organization: Faculty of Science, Chiba University Message-ID: References: <514A5DE1.10009@gmx.de> <831ub767wf.fsf@gnu.org> <83mwtu4p7c.fsf@gnu.org> <83vc8h313t.fsf@gnu.org> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: text/plain; charset=US-ASCII X-Trace: ger.gmane.org 1367039644 5464 80.91.229.3 (27 Apr 2013 05:14:04 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 27 Apr 2013 05:14:04 +0000 (UTC) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Apr 27 07:14:08 2013 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1UVxST-0002zB-TG for ged-emacs-devel@m.gmane.org; Sat, 27 Apr 2013 07:14:02 +0200 Original-Received: from localhost ([::1]:59836 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UVxST-0006Lx-BB for ged-emacs-devel@m.gmane.org; Sat, 27 Apr 2013 01:14:01 -0400 Original-Received: from eggs.gnu.org ([208.118.235.92]:48956) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UVxSO-0006Io-O4 for emacs-devel@gnu.org; Sat, 27 Apr 2013 01:13:58 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UVxSM-0005cw-Lh for emacs-devel@gnu.org; Sat, 27 Apr 2013 01:13:56 -0400 Original-Received: from mathmail.math.s.chiba-u.ac.jp ([133.82.132.2]:60259) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UVxSL-0005br-LS for emacs-devel@gnu.org; Sat, 27 Apr 2013 01:13:54 -0400 Original-Received: from church.math.s.chiba-u.ac.jp (church [133.82.132.36]) by mathmail.math.s.chiba-u.ac.jp (Postfix) with ESMTP id 852C1C055D for ; Sat, 27 Apr 2013 14:13:46 +0900 (JST) In-Reply-To: User-Agent: Wanderlust/2.14.0 (Africa) SEMI/1.14.6 (Maruoka) FLIM/1.14.8 (=?ISO-8859-4?Q?Shij=F2?=) APEL/10.6 Emacs/22.3 (sparc-sun-solaris2.8) MULE/5.0 (SAKAKI) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 133.82.132.2 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:159178 Archived-At: >>>>> On Sun, 24 Mar 2013 13:36:03 +0900, YAMAMOTO Mitsuharu 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; + } + 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;