emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: x-display-pixel-width/height inconsistency


From: Jan Djärv
Subject: Re: x-display-pixel-width/height inconsistency
Date: Sat, 27 Apr 2013 10:04:46 +0200

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 <address@hidden>:

>>>>>> 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;
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]