Bug 152978 - Improve support for multihead environments
Summary: Improve support for multihead environments
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: SWT (show other bugs)
Version: 3.2   Edit
Hardware: PC Linux
: P3 enhancement with 4 votes (vote)
Target Milestone: ---   Edit
Assignee: Arun Thondapu CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-08-07 10:50 EDT by Mathias Engelhardt CLA
Modified: 2015-11-09 13:35 EST (History)
4 users (show)

See Also:


Attachments
First proposal (62.07 KB, patch)
2006-10-19 12:09 EDT, Mathias Engelhardt CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mathias Engelhardt CLA 2006-08-07 10:50:48 EDT
Please provide a way to programmatically switch a (open) SWT Shell and the RCP workbench to a different screen in a multiheaded X environment.
Comment 1 Mathias Engelhardt CLA 2006-10-04 08:10:19 EDT
To be a little bit more precise:

With AWT, it is possible to get an array of all screen devices by calling GraphicsEnvironment.getScreenDevices(). The following code shows a JFrame on each screen:

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
for (GraphicsDevice device : ge.getScreenDevices()) {
  JFrame frame = new JFrame(device.getDefaultConfiguration());
  frame.setSize(300, 300);
  frame.setVisible(true);
}

To create the same result with SWT, I would use

for (Monitor m: Display.getDefault().getMonitors()) {
  Shell s = new Shell(display);
  s.setBounds(m.getBounds().x, m.getBounds().y, 300, 300);
}

This works perfectly well on Windows or an X xinerama configuration. But if X is configured to use a single X screen per monitor, there is no chance to open a Shell on another screen than the default.
Comment 2 Peter Centgraf CLA 2006-10-10 15:00:03 EDT
There was recently a request on the SWT mailing list for information about Mac OS multi-head setups.  AFAIK, Mac OS native APIs only support a mode like Xinerama, where all monitors are placed within a single coordinate space.  The relevant Carbon APIs:

http://developer.apple.com/documentation/GraphicsImaging/Reference/Quartz_Services_Ref/index.html

and Cocoa:

http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSScreen_Class/Reference/Reference.html
Comment 3 Mathias Engelhardt CLA 2006-10-11 03:36:57 EDT
This is my proposal to transparently support the GDK multihead API:
Extend the Display#getMonitors() method to return all monitors of the default display:

The Monitor class gets a new attribute xScreen which stores the handle of the xScreen of a particular Monitor object.

  public Monitor[] getMonitors() {
    checkDevice();
    Monitor[] monitors = null;
    Rectangle workArea = getWorkArea();

    int display = OS.gdk_display_get_default();
    int numScreens = OS.gdk_display_get_n_screens(display);
    if (numScreens > 0) {
      java.util.List monitorList = new Vector();
      for (int n = 0; n < numScreens; n++) {
        int screen = OS.gdk_display_get_screen(display, n);
        if (screen != 0) {
          int monitorCount = OS.gdk_screen_get_n_monitors(screen);
          if (monitorCount > 0) {
            GdkRectangle dest = new GdkRectangle();
            for (int i = 0; i < monitorCount; i++) {
              OS.gdk_screen_get_monitor_geometry(screen, i, dest);
              Monitor monitor = new Monitor();
              monitor.handle = i;
              monitor.x = dest.x;
              monitor.y = dest.y;
              monitor.width = dest.width;
              monitor.height = dest.height;
              monitor.screen = screen;
              if (i == 0 && workArea != null) {
                monitor.clientX = workArea.x;
                monitor.clientY = workArea.y;
                monitor.clientWidth = workArea.width;
                monitor.clientHeight = workArea.height;
              } else {
                monitor.clientX = monitor.x;
                monitor.clientY = monitor.y;
                monitor.clientWidth = monitor.width;
                monitor.clientHeight = monitor.height;
              }
              monitorList.add(monitor);
            }
          }
        }
      }
      monitors = new Monitor[monitorList.size()];
      for (int i = 0; i < monitorList.size(); i++) {
        monitors[i] = (Monitor) monitorList.get(i);
      }
    }
    if (monitors == null) {
      /* No multimonitor support detected, default to one monitor */
      Monitor monitor = new Monitor();
      Rectangle bounds = getBounds();
      monitor.x = bounds.x;
      monitor.y = bounds.y;
      monitor.width = bounds.width;
      monitor.height = bounds.height;
      monitor.screen = OS.gdk_screen_get_default();
      if (workArea != null) {
        monitor.clientX = workArea.x;
        monitor.clientY = workArea.y;
        monitor.clientWidth = workArea.width;
        monitor.clientHeight = workArea.height;
      } else {
        monitor.clientX = monitor.x;
        monitor.clientY = monitor.y;
        monitor.clientWidth = monitor.width;
        monitor.clientHeight = monitor.height;
      }
      monitors = new Monitor[] { monitor };
    }
    return monitors;
  }


There's a single modification necessary in the SWT API: Shell gets a new method setMonitor:

  public void setMonitor(Monitor monitor) {
    int toScreen;
    if (monitor == null || monitor.screen == 0) {
      toScreen = OS.gdk_screen_get_default();
    } else {
      toScreen = monitor.screen;
    }
    screen = toScreen;
    OS.gtk_window_set_screen(shellHandle, toScreen);
  }
Comment 4 Peter Centgraf CLA 2006-10-11 10:30:24 EDT
This sounds straightforward.  I have a few detail questions:

What semantics do you propose for setMonitor() if all Monitors share the same coordinate space?  Specifically, would the Shell arrive at a predictable position relative to the new Monitor?  (I would prefer that the Shell arrive at a position so that its new offsets from the origin of the new Monitor are equal to the previous offsets from the origin of the old Monitor.)

Will the Shell be resized or moved to fit within the bounds of the new Monitor, or will clients be responsible for this?  (I would prefer the latter, so that the event sequence for this call will be simple and predictable.)

Will there be a corresponding getMonitor() method on Shell?  (I hope so.  This requires annoying client code now, and that code will break under the multihead setups you intend to support.)

Is there any reason to make the screen field public, or can we keep it as a private field on the GTK implementation only?  (I think getMonitor() would handle this in a platform-independent way, so the screen handle can be private.)

Is there a parallel API to handle this kind of multi-head scenario under Motif, or would setMonitor() be unsupported in that environment?
Comment 5 Mathias Engelhardt CLA 2006-10-11 17:32:02 EDT
(In reply to comment #4)
> What semantics do you propose for setMonitor() if all Monitors share the same
> coordinate space?  Specifically, would the Shell arrive at a predictable
> position relative to the new Monitor?  (I would prefer that the Shell arrive at
> a position so that its new offsets from the origin of the new Monitor are equal
> to the previous offsets from the origin of the old Monitor.)
If all monitors share the same coordinate space (for example in a xinerama environment) setMonitor should position the shell's origin relative to the monitor's origin (as returned by monitor.getBounds()). The offset should be the same as on the old monitor, as you propose.

> 
> Will the Shell be resized or moved to fit within the bounds of the new Monitor,
> or will clients be responsible for this?  (I would prefer the latter, so that
> the event sequence for this call will be simple and predictable.)
I think the shell's size should be left untouched.

> Will there be a corresponding getMonitor() method on Shell?  (I hope so.  This
> requires annoying client code now, and that code will break under the multihead
> setups you intend to support.)
Yes. If it makes sense, there can be a corresponding getMonitor.

> 
> Is there any reason to make the screen field public, or can we keep it as a
> private field on the GTK implementation only?  (I think getMonitor() would
> handle this in a platform-independent way, so the screen handle can be
> private.)
The screen field could be made private. But then we would have to introduce a package scoped getter and setter to access the field's value from Display and Shell. Alternatively, the field could be made package scoped. There is indeed no reason to make the field public. Anyway, the field would only appear on the GTK implementation, not on the public API.

> Is there a parallel API to handle this kind of multi-head scenario under Motif,
> or would setMonitor() be unsupported in that environment?
I don't know whether Motif supports this kind of multi-head environment or not. 
Comment 6 Mathias Engelhardt CLA 2006-10-19 12:09:11 EDT
Created attachment 52324 [details]
First proposal

This is a partially working patch. It provides the desired behaviour on multiscreen X environments.
But there is still a problem when switching a workbench's shell to a new screen. The workbench window does not get fully displayed on the new screen. I think the problem comes from the usage of ProxyControls. The content composites of the views do not get expose events anymore after a switch to a new screen.
Comment 7 Mathias Engelhardt CLA 2007-01-16 05:29:10 EST
Are there any chances to get this integrated into the SWT main trunk?
Comment 8 Bogdan Gheorghe CLA 2015-11-09 13:35:04 EST
Arun - I know this is from way, way back but is there anything we can do here? (Someone pinged me about this bug).