Highlevel overview:

Tablet rotation things
only when there is a tablet attached.

Here is the OS X Display menu:

	Detect Displays
	Turn on mirroring
	--------------------------
	SyncMaster
		- 1280 x 1024, 60 Hz, Millions
	        - 1344 x ...
	--------------------------------
	Color LCD
		- 1024 x 1024 ...
	--------------------------
	Displays Preferences

	Color LCD means "laptop panel".

- GTK+ work.

	Allow applications to be notified whenever monitors are added
	or removed. Allow applications to get more detailed
	information about the connected monitors.

	The main complication is that XRRGetScreenResources() is very
	slow. We could call it only when the X server sends an event,
        but it's not desirable to have every application freeze for
        half a second. And certainly not desirable to have the X
        server block for n * 0.5 seconds.

	With the X server work below we should be fine just calling
        XRRGetScreenResources on startup and in response to events.

- X server work:

	X server needs to poll for whether a monitor is plugged
        in. Whenever it detects a change, it should do an EDID query,
        and cache the resulting information. That way XRRGetScreenResources()
	can be the speed of a normal roundtrip. It's desirable that
	normal client requests can still be processed during the EDID
        querying, but only a nice-to-have.

	Drivers need to work reliably. There could be substantial work
	here. For F9, possibly only the Intel driver can be made to
	work.

	Interrupts and events must be generated whenever something changes
	about the outputs, if necessary by polling.

	Events must be emitted whenever something changes, including when
	the reason for the change is a manual change.

	The maximum framebuffer must be dynamically changable.

- Control panel work:
	Capplet needs to be written. The main complications:

	- It needs to pay attention to events from the X server
	  and update itself, ie., add show new monitors if they become
	  available when the applet is shown.

	- It needs to store information under a key computed
	  from a monitor identifier. The complication here is that
          it's not completely clear how to do this in MateConf.

	- Would probably be worthwhile to drop libmate/libmateui from
	  the craplets.

- Marco work:
	- Marco is already Xinerama aware, but it needs to update itself
	  when monitors come and go.

- MATE panel work:
	- Is already Xinerama aware, but needs to listen and update itself
	  when monitors change.

- Evince work:
	- Make sure it deals sensibly with multiple monitors

- OpenOffice work:
	- Make sure it deals sensibly with multiple monitors

- An Xlib call to just return all the available information would be
  useful. At the moment we have to do a bunch of roundtrips to
  get the information. This is a would-be-nice though.

- A dbus service could be written that pops up the applet whenever a
  monitor. It should only pop up if the new monitor is unknown. This
  is at best a nice-to-have, and low priority in my opinion.


*******************  Marco

Havoc:

> I was just talking to bryan about this and "helping" him design it ;-)

> But I wanted to be sure and lobby for a fix window managers
> need. Basically right now the WM can't tell "physical" from
> "logical" monitors.

> A "logical" monitor is a desktop; it has its own panel, windows
> maximize to it, etc.

> A "physical" monitor is a piece of hardware.

> Sometimes people want to combine physical monitors into a video wall
> or just two monitors treated as one. Or at least a couple of noisy
> people in bugzilla want to do this.

> When people talk about a "Xinerama aware" app or WM they usually
> mean that all physical monitors are treated as logical monitors,
> while lack of Xinerama-aware means treating the entire X screen (all
> physical monitors) as one logical monitor.

> The problem is that the setting for "ignore Xinerama" or "don't be
> Xinerama aware" should be global to the desktop (GTK, all apps, WM)
> and should not be a window manager setting.

> Bryan thought people who wanted non-Xinerama-aware should just use
> fvwm, which may be right, but what I'd say is that if there is any
> setting for this, it should be desktop-global and in this monitor
> config dialog.

> It should not be a marco or Compiz option, but in some way an X
> option in short. The implementation could be either an X server
> feature or an EWMH hint or whatever, but it should be controlled by
> the monitor config dialog and used by apps, GTK, etc. in addition to
> used by the WM.

> People tend to insist this should be a WM option, but that's just
> busted, since GTK and apps also have Xinerama-awareness features.


******************* EDID

edid-decode enhancements:

- Rejects years <= 0x0f for all versions, but this should only be done
  for monitors claiming conformance to 1.4 (since 1.4 was released in
  2006). A monitor produced in 2005 should have 0x0f - it's the only
  reasonable thing to do.

- Uses 0x80 as the conformance mask for 1.4, should be 0

- Should read from stdin

- Should parse xrandr -verbose output more robustly

- Color depth computation is wrong. It uses the formula

	(edid[0x14] >> 3) + 2

  The correct formula to use is

	(edid[0x14] & 0x70) >> 3 + 4

-

-=-=-=-
Computing a display name from EDID information:

	  vendor = lookup_vendor (code);

	  if (dsc_product && !is_gobbledigook (dsc_product))
	  {
               if (vendor && !fuzzy_string_search (vendor, dsc_product))
	       	  prepend (vendor);
	  }
	  else
	  {
		if (vendor)
		   append (vendor);
		else
		   append ("Unknown");
	  }

          if (has size)
	  {
		convert_to_inches()

		append (" %d\"", inches)
	  }

(Does this internationalize at all)?

We also need the ability to get laptop names. The laptop panel may report
a manufacturer that has nothing to do with the laptop manufacturer.

Needed XRandr output properties:

- Modes that the monitor supports, or enough information that the
  client can go throught the list of modes for the relevant
  CRTC/Outputs and filter those out that the monitor can't support.

- The preferred mode, if any. Also useful if we could get a "strongly
  preferred" indication if it's an LCD with a fixed resolution.

- Sufficient information that a fairly specific identifier can be
  computed. The algorithm the client should use is:

	1 Have we seen exactly this monitor before? If yes, use
          settings for that.

	2 Have we seen a monitor with similar specs before? If yes,
	  use settings for that. (But don't save, unless the user
	  changes the settings).

	3 Otherwise, use some reasonable default for the monitor and
          save it.

  A setting should only be used if the CRTC/Output allows it. Ie,. if
  a user has installed a new video card, then previously-used settings
  may no longer apply, so this must be checked every time.

  (1) Implies that we really need a globally unique identifier for
  monitors. (2) is useful in an enterprise setting, but not absolutely
  critical, since (3) would still handle the majority of cases.

  There is a question here: Where are machine specific preferences
  stored? Havoc mentions three possibilities here:

     http://mail.gnome.org/archives/matecc-list/2001-October/msg00023.html

  I'm not sure if any of them are implementable at this point. Also
  (1) may mostly take care of the problem.


  Usecases:

  1. Fixed setup with some number of monitors.
     - They should be set to the correct mode on login.
       Note that this involves setting the right position in the
       framebuffer too.

       What if someone swaps two monitors? Users are going to expect
       that the images will switch position.

  2. Laptop being moved between home and work
     - Setups should be detected and the correct mode set, at least on
       login, but ideally when you put the laptop into the docking
       station.

  3. Laptop gets projector plugged in.

  Note the same model monitor can be used in two different ways. Ie.,
  at home, it's being used at one resolution, at work the same type of
  monitor is used at a different resolution.

  Simple solution:

  - The on-disk database is just a list of monitors. Each monitor has an
    associated mode. This has these problems:
         - If someone uses the same monitor model in two different ways.
         - If someone swaps the monitors around

  Better solution

  - The on-disk database is a list of configurations, where a
    configuration is a list of monitors and what outputs they are
    connected to, and the position in the framebuffer.

  - Picking a default configuration is then a matter of selecting the
    closest existing configuration from the database.

    	- If the stored configuration is a subset of the existing,
	  then use that - then pick the best mode available for the
	  rest of the monitors

	- If the stored configuration is a superset of the existing,
	  then use the projection of the configuration onto the monitors.

	- Pick the configuration with the most overlap in monitors.
	  Although, if a configuration differs only in what outputs
	  they are connected to, then those outputs should probably
	  get their original modes set.

  - Or maybe simply:

    - If there is an exact match, use it, if not, pick a default.

    - Picking a new default must never change the mode of any existing
      output.

******************* Capplet

Somehow the applet will find out that a new monitor is plugged in
(either through notification, or through a refresh button). When this
happens, this monitor is looked up in a database and if it is found,
some suitable mode is set.

Restrictions on the modes:

- Monitors that are already plugged in should not get their mode
  changed just because a new monitor is plugged in.

- If the exact configuration of monitors is known, and all the old
  monitors have the same mode as the known configuration, then just use
  the known configuration. Also do this, if the configuration is a
  subset of something known.

- Otherwise, if the configuration is a subset of a known configuration
  where the only difference is that existing monitors have different
  modes, then try and convert that mode to something we can know
  about. Maybe configurations should be stored in terms of edges that
  line up.

- Otherwise, just pick some good default for the mode, probably based
  on the EDID prferred mode if possible. By default cloning is
  probably best.

- How do virtual desktops interact with this?


g-s-d:

- On startup

     - It reads the configuration file into memory

       	    capplet --configure

     - It gathers the existing configuration from randr

     - If the existing config is in the file, set that mode

- On changes, including changes to the config file [this is crack]

     - Reread configuration file

     - Compare new configuration to database, if it is there, set the
       mode as appropriate

     - If a monitor was added, pop up a bubble

       	    capplet --show-bubble

       	    capplet --set-mode

capplet

- On changes

     - Update GUI

- When user changes something,

     - Write configuration to file

     - Signal gsd somehow

Schemes:
	- configuration file changes
	  - randr code will have to be shared between gcc and gsd

	- binary installed by gcc
	  - something will still have to listen for changes to pop
	    up the notification bubble.

Structure of capplet:

- There is a database on disk with monitors and their corresponding
  settings.

- On startup, this database is read into memory. When the user accepts
  new settings, it is written back to disk.

- When something changes about the settings

  - If new configuration is in the database, use that mode

  - Else, find all outputs that are now connected but weren't before,
    and set a default mode for them.

  - If GUI is running, update graphics.


  - Notification thing:
      - if

      - if the new configuration is found in the database, use it

  and added if they are not already there. Initial settings are
      1 what the output is already doing, if anything
      2 based on an existing sufficiently similar monitor, if possible
      3 some reasonable default.

- When the user changes settings in the GUI, the corresponding monitor
  in the database is updated.

- Whenever the GUI settings change, for all displayed monitors the
  possible modes are recomputed.

- Whenever a new monitor is selected in the GUI, it first gets all its
  possible modes computed based on the selections on other
  outputs. Then, if the possible modes include the existing choice of
  resolution, that is selected.

  Actually,

  - initially, the settings are copied from the current settings

  - whenever a gui setting changes for a monitor, all the other
    monitors get their list of choices set to whatever is possible
    given the chocie for the current monitor. A 'desired mode' is
    maintained, and the closest choice to that is displayed. Whenever
    the user actively selects something, that becomes the desired mode
    for that monitor.

- Required

  - Generate all outputs that are newly connected

    	     foreach_newly_connected (Configuration *before, Configuration *after,
	     			      OutputFunc);

  - A way to generate the best mode for a connected output

      	     existing best_mode() can probably be used

  - Given a list of modes, pick the one closest to a given mode.

      	     (a possibility here is: pick an exact match, if that's
	      impossible, then pick the best one with the same
	      width/height, if that's impossible, then just pick the
	      best mode on the list).

  - For a configuation, fix the mode for a subset of the outputs, then
    list the combinations for the rest of the outputs.

    	     An obvious possibility here is to simply list all possibilities,
	     then  weed out those that don't work. Is this too expensive?
	     It might be.

Structure of login time program:

- The configuration database is read

- The current hardware configuration is generated

- If the current configuration is found in the database, that mode is set.

- If it isn't found, then nothing changes.

     This could just be mate-screen-resolution-capplet --reset

*******************  Things that need to be done to the xrandr.patch:

===

XRRGetScreenResources() is a roundtrip and very slow (~0.5 s). GTK+
needs to keep information up-to-date by tracking events rather than
calling this function. In fact we probably can't call it at all unless
its performance improves significantly.

If EDID processing really has to be this slow, and we can't get
interrupts when monitors are plugged in, then we have a problem,
because we can't do anything this expensive once per second.


Detailed notes (but most of the patch should be rewritten):


=== FIXME in gdkscreen-x11.c in get_width_mm()

/* monitor pixel width / screen pixel width * screen_physical width */



=== Check for 1.2 library

The patch should check that the 1.2 version of the XRandR library is
available before using the functions. A possibility is to not use any
RandR unless 1.2 is available, another is to conditionalize the code.

The most sane thing is probably to just require 1.2.

On the other hand, installing a newer gtk+ on a system with older X is
probably not that unusual, so maybe it's better to do the full 1.0,
vs. 1.1 vs 1.2 check.

For now it just requires 1.2.

Actually, this might be fine because the only place where we make use
of a 1.1 library is in the _gdk_x11_screen_size_changed() function,
but there we have a fallback that just updates the variables in the
Screen struct itself.

So, only defining HAVE_RANDR if we detect 1.2 should be ok.

=== Monitor information available

- Subpixel information. This should be set automatically for the fonts and
  store under the name of the monitor. If the user changes the font
  configuration, that change should also be stored under the monitor name.

- When a monitor we don't know about is plugged in, a configuration should
  be generated:

	- Screen size, computed based on the location of the screens

	- RGBA information

	- Whether the screen has a panel on it

	- If there is a conflict between stored information and EDID,
          the stored information wins



New API so far:

(* monitors_changed) signal
gdk_screen_get_monitor_width_mm()
gdk_screen_get_monitor_height_mm()
gdk_screen_get_monitor_name() => Note this is the output (eg. "DVI-0")

We should probably also have
get_manufacturer()
get_serial()
get_resolutions()

etc.

Should there be a GdkMonitor object that would correspond to an
output? Or maybe GdkOutput?

screen_list_monitors()


*************************** Issues XRandR/Xserver

- We need polling in the X server, whenever something changes, X must
  recompute the information and cache it, then send an event. Note the
  situation where the user disconnects and reconnects a monitor within
  the polling interval. The event could missed in that case since the polling
  cannot do a full EDID query. Difficult to see a way around this.

  Actually, DDC allows random access, so it should be possible to just
  read theq vendor id and manufacturer codes. This can be done once a
  second without a problem. The polling should be turned off in power
  saving mode anyway.

  - Driver work:

  - Intel driver:

    - EDID information is not reported for VGA when the output is not
      turned on (i945 laptop).

    - Screen size must be dynamically changable. (No xorg.conf changes
      should be required).

    - Make use of ACPI information when possible.

      Adam has code on his freedesktop page.

    - i830 laptop can be put in a state where XRandr reports that no
      outputs are connected to a CRTC, but the panel is on.

      	      - Plug in VGA
	      - xrandr --auto
	      - xrandr --output VGA --off
	      - run chk
	      - xrandr --verbose will now not report any outputs as turned on
	      - run chk again - all screens will be turned off

    - Small Sun monitor - an 1152x921 mode is generated, but the
      monitor doesn't handle that. The monitor itself only claims to
      handle 1152x920.  It doesn't look to me like there is anything
      in the EDID information that would indicate that it could handle
      1152x921.

      This happens with a radeon as wellso it may be a bug in the
      generic X server EDID parsing. The X server apparently
      interpretes the standard timing 1152x920 as 1152x921.

      This happens because the X server uses

      	    hsize * 4 / 5

      which gives 921 for 1152. By using

      	    (hsize / 5) * 4

      you get 920. The 66 Hz version can bet set, the 76 Hz mode gets
      sync out of range. (Would be interesting to find out whether the
      1152x920 ModeLine would allow the 76 Hz version to be set).

  This is for the ATI driver as shipped in F8:

  - XRRGetScreenResources() takes half a second.

    - Adam has now removed a workaround that caused some of the slowdown.

  - If a DVI monitor is disconnected, you get "Unknown" for connection
    status.

  - If a VGA monitor is plugged in, then EDID information is not
    available, even after running xrandr --verbose. The monitor has
    to be plugged in at driver startup time, apparently.

  - Logging out and logging back in often results in some random mode being
    set. We need mode selection to not be completely screwed up.
    Currently it is.

  - The set up at server startup needs to be fixed. *If* randr actually works,
    then we might be able to do something sensible.

  - We need to revisit the idea that many monitors have broken EDID data.
    This may be less widespread than previously believed.

- It may be useful to return the connector names as identifiers instead
  of relying on UTF-8 strings. Ie., have an enum

	{ UNKNOWN, OTHER, DVI, VGA, HDMI, ...,  }

  in addition to the string. The difference between UNKNOWN and OTHER is that
  UNKNOWN means the driver doesn't know, whereas OTHER means it is something
  not listed in the enum (which could be listed in a later version).

- Mouse cursor should be confined to the visible area. (It is already, I think)

- It looks like EDID information is only available for one output
  even though it is actually read according to the log file.
  (nv, intel drivers)


*********************************



DONE:

Server work:

    - i830 laptop incorrectly reports BadMatch when you configure the
      CRTC to drive both VGA and LVDS with the 1024x768 mode that both
      outputs can handle. (It should return 'failed' if it can't do
      that). Same for i945 laptop. It seems as if the same CRTC can't
      drive more than one output at the same time on Intel.

      This was a client bug, but the documentation for SetCrtcConfig
      should say that BadMatch will be returned if the outputs aren't
      clones.

GTK+ patch is in now.

=== Add helper function


+  if (screen_x11->randr12)
+  {
+       XRRScreenResources *sr;
+    XRROutputInfo *output;
+       gchar *retval;
+
+    sr = XRRGetScreenResources ( screen_x11->xdisplay,
+                                 screen_x11->xroot_window );
+
+    output = XRRGetOutputInfo ( screen_x11->xdisplay,
+                                sr,
+                                (RROutput)screen_x11->act_outputs[monitor_num]
);

  Might be worthwhile to factor this out into a
  gdk_screen_get_output_info (screen, monitor_num)
  helper function ?

Instead of cutting and pasting all over creation

* Calling XRRGetScreenResources all the time is not going to fly. It
  takes hundreds of milliseconds ... Even if it didn't, it wouldn't
  be acceptable to do all those roundtrips.


=== Some g_prints left


=== Version check

Should be (maj > 1) || (maj == 1 && min >= 2)


=== Grep for TODO


=== Setup XRRSelectInput()

  You should call XRRSelectInput() at the same place where you are
  calling XSelectInput() right now. The right place to handle the
  XRandr events is the huge switch in gdkevents-x11.c:gdk_event_translate
  Check out how other extension events are handled there, like
  XKB, or XFixes.


=== Lots of variable naming issues, such as act_output and noutput

=== Needs to select the input, and hook it up to the signal

=== Add version markers to API

=== API to turn monitors on and off?

- DPMS not exposed through randr, maybe should be

       - DPMS is presumably a property of either an
         output or a CRTC. Logically it's an output.

- Need events when DPMS happens. Exposing the "screen saving on" on
  dbus may not be good enough.

=== Why does init_multihead_support() start by freeing monitors and
outputs?

=== Do we disable Xinerama support entirely when 1.2 is in use?

=== We should expose information about what parts of the screen monitors
are viewing.

=== Make use of the EDID information?


-- details for X server --

In nv driver SorSetOutputProperty should return TRUE for unknown
properties. (Like the Intel driver does).

Detecting plugged in

- Periodically poll
  -

  - One ddc probe takes 5 ms, according to a comment in the intel
    driver. Running this twice a second would mean spending 1% of
    overall time doing ddc polling, which is almost certainly not
    acceptable.

    1) Async I2C:

	void I2CProbeAsync(..., callback, data);
        Bool I2CPending()
	void I2CUpdate()

      In Dispatch, call I2CUpdate()
      Before going idle, do

            while (I2CPending())
                 I2CUpdate()

      Would need
      	    RegisterDispatchFunction()  (Is this called Wakeup?)
	    RegisterIdleFunction()

      Note the idle function should have the option of saying:
      "check if something else happened; if not, call me again" and
      "ok, I'm done - go idle". Otherwise, we would be blocking for
      5 ms whenever the X server went idle. So actually the idle
      function should be

      	       if (I2CPending())
	       {
			I2CUpdate();
			return TRUE;  /* call me again */
               }
               else
	       {
			return FALSE; /* I'm done */
               }

      What happens if another I2C requests come in while an async one
      is pending? Most likely we simply finish whatever is going on,
      then process the new request.

      What happens if an X request takes so long that we get timeouts on
      the i2c bus? Good question. Need to read the VESA ddc spec.

    2) Run the polling in a separate thread.

       Probably crack.

    3) Run the polling less, maybe once every three seconds.

-- details for control panel --
Screen changes
       - Currently it is polling via rw_screen_refresh(), which will always emit
         a screen-changed event. In reponse to this event the capplet currently
	 checks whether anything changed physically about the setup. This means
	 the capplet can't react to external changes to modes. On the other hand
	 if it didn't
Disallow combinations that would exceed the screen ranges.
   - Note rotations

Give rw objects stable positions in memory so that they can be cached
across screen_changed events.

Add Clone Mode

Drag and drop for the monitors
     - 2 dimensional layout

Store make and model in monitors.xml, then if serial numbers don't
match, fall back to a make and model match. Users with an nfs mounted
home directory should not have to reconfigure for each new system they
log in to.

Make sure text is scaled correctly

Need to sanitize naming
     RWOutput vs Output	- should probably be OutputInfo
     rate vs. freq - decide on one

Should probably reconsider the use of null terminated arrays.
Maybe lists would be better.

Pick a fixed scale, so that two 1024x768 don't look like two 6x4.
     - An alternative would be to draw a checkerboard pattern
       below the monitors.



done:

Add rotation

Disable panel checkbox for now

Patch into mate-desktop

Find out how to share code between gcc and gsd

Make it assign coordinates correctly
     - including computing correct screen size

