Java Swing - mouse pointer "shifted" on context menu when JFrame is maximized - linux

I encoutered a strange behaviour of handling mouse position by Swing when maximizing JFrame:
When I execute this very simple code...
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
JMenuBar menubar = new JMenuBar();
JMenu menu = new JMenu("File");
menu.add(new JMenuItem("New"));
menubar.add(menu);
frame.setJMenuBar(menubar);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
... I can normally click File (first click - press,release) -> New (second click). But when I maximize JFrame and click on File - context menu disappears on mouse release immediately.
Moreover when I hold mouse button - to prevent disappearance - I must move my mouse much further to focus on New item.
The red dot represents area (more or less) where I must move my mouse to focus on New after pressing File and holding mouse button.
I've observed the same behaviour when using "right-click context menu" for example when right clicking on chart from JFreeChart.
I thought it was JDK problem because I used Oracle's JDK, but after installing OpenJDK I have the same results.
Did somebody observe this strange behaviour? Or am I missing something obvious?
I use:
1.7.0_147-icedtea (or 1.7.0_04 for java-7-oracle)
OpenJDK Runtime Environment (IcedTea7 2.0) (7~b147-2.0-0ubuntu0.11.10.1)
OpenJDK 64-Bit Server VM (build 21.0-b17, mixed mode)
Linux Mint 12 (lisa) GNOME 3.2.1

Yes - this is a bug in JDK7 as #nIcE cOw mentioned.
I've installed JDK6 and I couldn't reproduce this bug.
java version "1.6.0_23"
OpenJDK Runtime Environment (IcedTea6 1.11pre) (6b23~pre11-0ubuntu1.11.10.2)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)

There is also a workaround when it is necessary to use the Oracle Java 7 (e.g. when using JavaFX). Just add the following lines of code to your window/frame class:
if (Arrays.asList("gnome-shell", "mate", "other...").contains(System.getenv("DESKTOP_SESSION"))) {
try {
Class<?> xwm = Class.forName("sun.awt.X11.XWM");
Field awt_wmgr = xwm.getDeclaredField("awt_wmgr");
awt_wmgr.setAccessible(true);
Field other_wm = xwm.getDeclaredField("OTHER_WM");
other_wm.setAccessible(true);
if (awt_wmgr.get(null).equals(other_wm.get(null))) {
Field metacity_wm = xwm.getDeclaredField("METACITY_WM");
metacity_wm.setAccessible(true);
awt_wmgr.set(null, metacity_wm.get(null));
}
}
catch (Exception x) {
x.printStackTrace();
}
}
This code snippet is based on a workaround from the Netbeans developers.

I would like to complement the solution given by problemzebra.
As it still happens for me with any swing application on Linux (using Cinnamon desktop), even on Java 6 (update 45)
The issue will reoccur every time I move the window or resize it, so you need to reapply the workaround every time the window changes. I created the following class and use it whenever I create a new window:
class LinuxWindowFix implements WindowStateListener {
private final String desktop;
private Field metacity_wm;
private Field awt_wmgr;
private boolean applyFix;
private static LinuxWindowFix instance = new LinuxWindowFix();
public static LinuxWindowFix getInstance() {
return instance;
}
private LinuxWindowFix() {
applyFix = false;
List<String> linuxDesktops = Arrays.asList("gnome-shell", "mate", "cinnamon"); //add more desktop names here.
desktop = System.getenv("DESKTOP_SESSION");
if (desktop != null && linuxDesktops.contains(desktop.toLowerCase())) {
try {
Class<?> xwm = Class.forName("sun.awt.X11.XWM");
awt_wmgr = xwm.getDeclaredField("awt_wmgr");
awt_wmgr.setAccessible(true);
Field other_wm = xwm.getDeclaredField("OTHER_WM");
other_wm.setAccessible(true);
if (awt_wmgr.get(null).equals(other_wm.get(null))) {
metacity_wm = xwm.getDeclaredField("METACITY_WM");
metacity_wm.setAccessible(true);
applyFix = true;
}
} catch (Exception ex) {
//ignore
}
}
}
#Override
public void windowStateChanged(WindowEvent e) {
try {
awt_wmgr.set(null, metacity_wm.get(null));
} catch (Exception ex) {
//ignore
}
}
public void apply(Window w) {
if (!applyFix) {
return;
}
w.removeWindowStateListener(this);
w.addWindowStateListener(this);
}
}
Simply call this for every window you create and it will work as expected.
LinuxWindowFix.getInstance().apply(myWindow);

Related

MvvmCross and UIButton.Selected UISegmentedControl Bindings, iOS

In a cross platform Xamarin app built with the MvvmCross framework I'm using a ToggleButton Widget in an Android .axml layout. I've bound the Checked property to a View Model property using a converter using the following binding syntax:
Checked MarketBuySellViewModel.Direction, Converter=DirectionBool, ConverterParameter='Sell'
Everything works well. On the iOS side, it appears you can use UIButton as a ToggleButton by using the Selected property. This implies that the following binding should achieve what I want on iOS:
set.Bind (SellButton).For(b => b.Selected).To (vm => vm.MarketBuySellViewModel.Direction).WithConversion("DirectionBool", "Sell");
I don't get any binding errors in the application output but the binding itself doesn't seem to work. Clicking the button doesn't set the Direction property and setting the direction to a different value does not set the Selected property on the UIButton.
Do I need to create a Custom Binding or am I simply setting up the binding incorrectly?
I also tried using a UISegmentedControl to achieve the same effect. Is binding to this control supported at all in MvvmCross? I don't see any reference to it in the source code. Does this mean I need to create custom bindings for it too?
For the UIButton, I don't believe there's any included Selected binding built into MvvmCross. Because of this - and because Selected doesn't have a simple paired event SelectedChanged, then I believe Selected binding should work one-way (from ViewModel to View) but not two-way.
There is a binding for the On of a UISwitch control and that's the control I've seen used most in these situations.
If you wanted to add a custom 2-way binding for Selected then I guess you'd have to do this using the ValueChanged event (but would need to check that is correct).
To do so, you'd just build a target binding something like:
public class MvxUIButtonSelectedTargetBinding : MvxPropertyInfoTargetBinding<UIButton>
{
public MvxUIButtonSelectedTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
var view = View;
view.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = View;
if (view == null)
return;
FireValueChanged(view.Selected);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
and this could be registered in Setup in protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry) using something like:
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUIButtonSelectedTargetBinding), typeof(UIButton),
"Selected");
Similarly, I don't believe anyone has added a two way UISegmentedControl binding yet - but would happily see one added.
Building a two way UISegmentedControl binding would be quite straight-forward - you'd just have to bind to the pair SelectedSegment and ValueChanged - with code similar to above.
Alternatively, you could switch to using a custom MySegmentedControl which had a nicer Value`ValueChanged` pair which would automatically work without a custom binding - e.g.:
public class MySegmentedControl : UISegmentedControl
{
// add more constructors if required
public int Value
{
get { return base.SelectedSegment; }
set { base.SelectedSegment = value; }
}
}
If any or all of these custom bindings are needed, then the Mvx project is happy to get these bindings added as issues or pull requests along with test/demo UIs in the https://github.com/slodge/MvvmCross-Tutorials/blob/master/ApiExamples/ApiExamples.Touch/Views/FirstView.cs project
Could be helpful to someone else, so i'm sharing my experience. I needed a two way binding for UISegmentedControl.SelectedSegment property to a ViewModel. The one way biding (ViewModel => View) works by default. I couldn't able to properly utilize the solution proposed by Stuart - to subclass the UISegmentedControl. I tried to ensure that the linker does not rip off the new custom control code, but this didn't help me a bit. So a perfectly viable solution is the one with MvxPropertyInfoTargetBinding. Here is the code working ok for me:
public class MvxUISegmentedControlSelectedSegmentTargetBinding : MvxPropertyInfoTargetBinding<UISegmentedControl>
{
public MvxUISegmentedControlSelectedSegmentTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
this.View.ValueChanged += HandleValueChanged;
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = this.View;
if (view == null)
{
return;
}
FireValueChanged(view.SelectedSegment);
}
public override MvxBindingMode DefaultMode
{
get { return MvxBindingMode.TwoWay; }
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
if (isDisposing)
{
var view = this.View;
if (view != null)
{
view.ValueChanged -= HandleValueChanged;
}
}
}
}
public class Setup : MvxTouchSetup
{
...
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterPropertyInfoBindingFactory(typeof(MvxUISegmentedControlSelectedSegmentTargetBinding), typeof(UISegmentedControl), "SelectedSegment");
}
}

org.eclipse.swt.browser.Browser does not open in Eclipse RAP application

Wonder if somebody can help me with this. I am trying to open an embedded browser in an Eclipse RAP applications. All examples I have seen look something like:
link.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
try {
Browser b = new Browser(parent, SWT.NONE);
b.setText("<html><body>This is Unicode HTML content from memory</body></html>");
} catch (SWTError e) {
// Error handling here
}
}
});
That doesn't do anything (visually) though. When I replace the Browser with ExternalBrowser like so:
link.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent event) {
try {
int browserStyle = ExternalBrowser.LOCATION_BAR;
ExternalBrowser.open( "myPage", "http://www.stackoverflow.com", browserStyle );
} catch (SWTError e) {
// Error handling here
}
}
});
It works. Although not exactly as desired.
I am using Eclipse RCP 1.4.2 on OS X 10.8.2.
Any insight is highly appreciated.
When you create a new widget, you have to trigger a re-layout to make it visible. Depending on your layout, it may be sufficient to call parent.layout(). If the parent is also contained in a layout and shrunken to its preferred size, you will have to call layout() on its parent. If unsure, layout the top-level shell.

Lwuit touch screen strange behaviour

I am making an application using LWUIT.
There is a form
There is a list embedded on the form.
The list has 5 elements.
Initially, when I first load the app, if I choose the 1st element, 2nd gets chosen; when I choose the second the 3rd gets chose and and so on (Weird!)
I am not able to click any button on the screen either
next what I do is, shift to a different from using arrow keys (of the keyboard... I am running the app on a simulator btw)
Then I come back to the first form and now everything works as expected(no weird behaviour).
What could be the issue?
I am using Sun Java Micro Edition SDK 3.0 (default touch screen for testing)
My code is:
List dummy = new List();
dummy.addItem("wewerwer");
dummy.addItem("wewerdswer");
dummy.addItem("wewqweerwer");
dummy.addItem("dscxwewerwer");
dummy.addItem("jhgwewerwer");
mainListForm.setLayout(new BorderLayout());
mainListForm.addComponent(BorderLayout.CENTER,dummy);
mainListForm.show();
What could possible be going wrong here?
UPDATE 1
I think there is a bug here. I have attached the complete code below along with the screen shot
import javax.microedition.midlet.*;
import com.sun.lwuit.*;
import com.sun.lwuit.events.*;
import com.sun.lwuit.plaf.UIManager;
import com.sun.lwuit.util.Resources;
public class Demo extends MIDlet implements ActionListener {
private Form mForm;
List abc;
public void startApp() {
Display.init(this);
try {
Resources r = Resources.open("/Test.res");
UIManager.getInstance().setThemeProps(r.getTheme(
r.getThemeResourceNames()[0])
);
} catch (Exception e){
System.out.println(e.toString());
}
if (mForm == null) {
Button click = new Button("Press me!");
click.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("I have been pressed");
}
});
abc = new List();
abc.addItem("Str1");
abc.addItem("Str2");
abc.addItem("Str3");
abc.addItem("Str4");
abc.addItem("Str5");
abc.addItem("Str6");
Form f = new Form("Hello, LWUIT!");
abc.addActionListener(this);
f.addComponent(abc);
Command exitCommand = new Command("Exit");
f.addCommand(exitCommand);
f.addCommandListener(this);
f.addComponent(click);
f.show();
}
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
public void actionPerformed(ActionEvent ae) {
System.out.println(abc.getSelectedIndex());
}
}
So now when I click on 'Str1' of the list Str2 gets selected and so on.
IDE: Netbeans
Emulator: Default Touch screen phone
On the action event set the list to active again after the event by invoking setHandlesInput(true)
OK....so this is how you resolve it.
After the form is displayed remove the list from the form and again add it to the form and then repaint the form.
Earlier Code
1) form.addComponenet(BorderLayout.center,list);
2) form.show();
Word Around for the problem
1)form.addComponenet(BorderLayout.center,list);
2)form.show();
3)form.setScrollable(false);
I know its kind of strange, but this way the list index selection works smooth for touch screen phones.

How to make my Boot.java class as main always on top where i have other processes causing troubles in Java?

I have this main.Boot which is actually a splash screen requires to be always on top of everything. But in my case what happening is it gets lost and main.main gets the first position which even do not have any setAlwaysOnTop(true);
How can i set main.Boot always on top?
Boot.java:
package main;
public class Boot
{
public static void main(String[] args)
{
try {
String myCmd;
// Layer 2 : it can be any other third party Java applications getting launched
// here its just one example used simple another JWindow...
myCmd = "java -cp /tmp/dist/AnotherProcess.jar main.main";
Runtime.getRuntime().exec(myCmd);
System.out.println("Running: " + myCmd);
} catch(Exception e) {
System.out.println(e);
}
myTimer(); // just a timer counting 40 seconds doing nothing else
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
window = new JWindow();
....
//setFocusable(true);
window.pack();
window.setLayout(new BorderLayout());
window.setSize(screen.width, screen.height+1);
window.setLocationRelativeTo(null);
window.setAlwaysOnTop(true); // Layer 1
// (always on top) > but it gets behind
// what ever was launched using .exec(..)
window.setVisible(true);
}
}
JFrame/JWindow doesn's support Modality correctly back to the Native OS this is job for un_decorated JDialog with following two methods
setAlwaysOnTop
setModal(true)
Notice not possible (Windows OS) to block keys Atl + F4 or Ctlr + Alt + F4
It may not be supported on your platform.
From the docs:
Note: some platforms might not support always-on-top windows. To
detect if always-on-top windows are supported by the current platform,
use Toolkit.isAlwaysOnTopSupported() and isAlwaysOnTopSupported(). If
always-on-top mode isn't supported by the toolkit or for this window,
calling this method has no effect.

How to access the Keyboard in an Eclipse RCP / LWJGL app?

I am working my way through the NeHe OpenGL examples, using the LWJGL for the OpenGL binding inside an Eclipse RCP application.
My OpenGL graphics are displayed inside the RCP canvas, not in a separate window.
Lesson 07 shows how to use the keyboard. If I try to do a:
Keyboard.create();
I get an error that the (OpenGL) "Display" has not been created.
If I create an OpenGL "Display" with org.lwjgl.opengl.Display.create(), then I get a new Window.
So how do I access the Keyboard without creating a new Window?
You cannot use the Keyboard without a Display, because of how LWJGL works behind the scenes. The best way is to just use AWT events. You can write your own input class, that could go something like this.
public class Input implements KeyListener {
private boolean aDown; //is the A key down?
//Ect, for all needed keys
public void keyPressed(KeyEvent ke) {
switch (ke.getKeyCode()) {
case KeyEvent.VK_A: aDown = true; break;
//and so on for all other needed keys.
}
}
public void keyReleased(KeyEvent ke) {
switch (ke.getKeyCode()) {
case KeyEvent.VK_A: aDown = false; break;
//and so on for all other needed keys.
}
}
public void keyTyped(KeyEvent ke) {} //Do nothing
public void isADown() {return aDown;}
}

Resources