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 GConf. - Would probably be worthwhile to drop libgnome/libgnomeui from the craplets. - Metacity work: - Metacity is already Xinerama aware, but it needs to update itself when monitors come and go. - GNOME 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. ******************* Metacity 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 metacity 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/gnomecc-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 gnome-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 gnome-desktop Find out how to share code between gcc and gsd Make it assign coordinates correctly - including computing correct screen size