I'm writing an SWT app using JOGL and the SWT/AWT bridge, and I'm trying to create multiple GLCanvas objects inside a Composite, which I'm then trying to put inside a tab. When it works, it looks like this:
But most of the time (about 75% perhaps, at random) it crashes with the following error message:
A fatal error has been detected by the Java Runtime Environment:
SIGSEGV (0xb) at pc=0x0024843a, pid=8618, tid=2345560944
JRE version: 6.0_22-b22
Java VM: OpenJDK Server VM (20.0-b11 mixed mode linux-x86 )
Derivative: IcedTea6 1.10.2
Distribution: Ubuntu 11.04, package 6b22-1.10.2-0ubuntu1~11.04.1
Problematic frame: C
[libpthread.so.0+0x843a] __pthread_mutex_lock+0x11a
I've also tried it with just one canvas instead of two, and I still get the same random crash. Occasionally, I get this error message instead:
java: tpp.c:63: __pthread_tpp_change_priority: Assertion `new_prio == -1 || (new_prio >= __sched_fifo_min_prio && new_prio <= __sched_fifo_max_prio)' failed.
Presumably there's a threading problem, maybe a race condition? Strangely enough, if I try to put the composite straight onto the shell instead of onto a tab, it works fine (or at least I haven't seen it crash).
The relevant bit of code looks like this:
tabFolder = new CTabFolder(shell, SWT.BORDER);
tabFolder.setSimple(false);
final Composite composite = new Composite(tabFolder, SWT.NONE);
composite.setLayout(new FillLayout());
new VisualizerCanvas(composite, MeshFactory.loadObj("meshes/teapot_sealed.obj"));
new VisualizerCanvas(composite, MeshFactory.loadObj("meshes/duck.obj"));
final CTabItem item = new CTabItem(tabFolder, SWT.CLOSE);
item.setText("Test");
item.setImage(new Image(display, "img/test.jpg"));
item.setControl(composite);
The VisualizerCanvas constructor looks like this:
public VisualizerCanvas(Composite parent, Mesh mesh)
{
// Set up the canvas
GLProfile glProfile = GLProfile.getDefault();
GLCapabilities glCapabilities = new GLCapabilities(glProfile);
glCapabilities.setDoubleBuffered(true);
glCapabilities.setHardwareAccelerated(true);
glCanvas = new GLCanvas(glCapabilities);
glCanvas.addGLEventListener(this);
// Create the embedded AWT frame using the SWT/AWT bridge
Composite composite = new Composite(parent, SWT.EMBEDDED | SWT.BORDER | SWT.NO_BACKGROUND);
composite.setLayout(new FillLayout());
Frame frame = SWT_AWT.new_Frame(composite);
frame.add(glCanvas);
// Add an animator to automatically update the canvas at 30fps
animator = new FPSAnimator(glCanvas, 30);
animator.add(glCanvas);
animator.start();
this.mesh = MeshFactory.normalizeMesh(mesh);
}
Am I doing something I shouldn't with SWT widgets/composites?
Finally solved the problem myself. Turns out it was indeed a race condition - I'm developing in Eclipse on Linux, and I need the following piece of code to prevent Linux window events getting lost:
static {
GLProfile.initSingleton(false);
}
I'd already put this in my VisualizerCanvas class, but not in my Visualizer class (the first piece of code). Presumably GLProfile and VisualizerCanvas were in a race to be loaded by the JVM, and GLProfile would sometimes win, resulting in a crash.
Related
I'm working in a GUI Java Application in Eclipse IDE. I'm using Window Builder to speed the UI design.
As a part of refactoring, I've changed the sequential and repetitive code to encapsulated versions in other packages, this breaks the "Design" view, but does not affect the application itself.
The problem is that any change made to the ui needs to be seen through the compiled app, (after compile and run the app I mean), and I need to manually relaunch app any time I make a change.
So, my question is:
Is there any plugin or tool that detects changes and automatically relaunches the application, as nodemon does in Nodejs applications.
Thanks in advance.
There is no such tool AFAIK. The next thing is to place the program in Debug mode add a refresh button to redraw the widget and hope for the best (the JVM might or might not be able to re-initialize your class).
Alternatively, you can create a class that monitors the filesystem for recompiles and then restarts your application.
All bleh...
The best tip I can give you is to redesign your application in a way that Windowbuilder can understand.
I assume you have refactored your UI into multiple modular parts. If your UI consists of e.g. a Customer Detail panel and a Customer List panel, you might want to develop each of these separately. This is something WB can handle fine.
Create your modular UI classes in such a way that WB can understand them by subclassing a Widget (preferably Composite). The class below can be added to the palette of Windowbuilder and dragged into your 'composite' application.
public class MyCustomerDetail extends Composite {
public MyCustomerDetail(Composite pParent, int pStyle) {
super(pParent, pStyle);
GridLayout gridLayout = new GridLayout(2, false);
setLayout(gridLayout);
Label label = new Label(this, SWT.NONE);
label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
label.setText("Customer Name");
Text name = new Text(this, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
name.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
}
}
Don't make a POJO class with a GUI method. The following class cannot be handled by WB and is of bad taste altogether.
public class MyCustomerDetail {
public void createUI(Composite pParent) {
Label label = new Label(pParent, SWT.NONE);
label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
label.setText("Customer Name");
Text name = new Text(pParent, SWT.SINGLE | SWT.LEAD | SWT.BORDER);
name.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
}
}
This is my code
shell.setFullScreen(true);
shell.setMaximized(true);
shell.setText("SD Cyber Cafe");
shell.setLayout(new FormLayout());
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Image oriImage = new Image(display, "C:\\Users\\LAPTOP-SYAMSOUL\\Desktop\\lockscreen_app\\main_bg.jpeg"); //should get from database
//System.out.println(screenSize.width);
Image newImage = new Image(display, oriImage.getImageData(100).scaledTo(screenSize.width, screenSize.height));
shell.setBackgroundImage(newImage);
When I run the app via eclipse, it works fine...
But after I exported to Runnable JAR the background Image is not scaled... why??
This is what I expected:
..
..
..
But currently it appear like below: ( I don't want this):
It is hard to say for sure from this code but Toolkit is a Swing/AWT method and should not be used with SWT. It may well be giving the wrong values.
Get the primary display size using something like:
Rectangle displayArea = shell.getDisplay().getPrimaryMonitor().getBounds();
which tells you about the main (primary) monitor or
Rectangle displayArea = shell.getMonitor().getBounds();
which tells you about the monitor on which the shell will appear (may be different if there are several monitors).
I have a slightly complicated JavaFX GUI with the following component structure (simplified) as shown below. You will see that a SwingNode is used to contain the main bulk of the application, but I cannot tell you the design principle behind this since I didn't write the original code.
I am aware of various cautions about occasional odd behaviour when Swing & JavaFX are mixed, but there isn't the time at present to re-write the UI. The application is built to run on a Windows 7/8/10 platform, and what I'm seeing is as follows:
(a) On three different platforms I've tested (Windows XP native, Windows 7 VM, Windows 8 VM, different size monitors), when the application's Windows "maximize" decoration is clicked, the application resizes OK (by which I mean it is slightly jumpy and delayed, but the actual repainting to fill the screen is done correctly).
(b) However, on one further platform, the 'maximize' causes the entire content of the Stage to go white, and doesn't repaint properly until, say, a menu or one of its items is clicked. The machine in question is a Dell Optiplex 64-bit Windows 7 Pro SP1 with a DVI monitor of 1920 x 1080 sourced from an Intel HD Graphics 4600. ClearType is set to ON, and the version of Java is 1.8.0_73_b02.
There is one further question on SO regarding this issue, but it was created in June 2015 and never answered, so I'm not sure what to think.
Has anyone else come across this issue and/or feels able to comment on what might be causing it ? Is there some sort of 'revalidate/repaint' code, or JavaFX equivalent, which might be worth me trying as a workaround ?
public class Main extends Application
{
private SwingNode mainSwingNode = new SwingNode();
private JPanel mainPanel = new JPanel();
public void start(Stage primaryStage) throws Exception
{
BorderPane parent = new BorderPane(mainSwingNode);
Scene scene = new Scene(parent, 1024, 768);
// Build Swing components
SwingUtilities.invokeLater(() ->
{
createAndShowGUI();
mainSwingNode.setContent(mainPanel);
});
primaryStage.setScene(scene);
primaryStage.show();
}
public void createAndShowGUI()
{
mainPanel.setLayout(new BorderLayout());
// Setup canvas area & canvas rulers
mCanvasTabbedPane.setPreferredSize(new Dimension(800,600));
mainPanel.add(mCanvasTabbedPane, BorderLayout.CENTER);
menubar.initForActionsMap(menuActionsMap);
// Listen for property changes for site to enable/disable menus
ProjSingleton.getInstance().addPropertyChangeListener(menubar);
mainPanel.add(menubar, BorderLayout.NORTH);
// Setup show/hide sidebar button
btnShowSidebar = new JButton(menuActionsMap.get(ShowSidebarAction.class));
menubar.add(Box.createHorizontalGlue());
menubar.add(btnShowSidebar);
btnShowSidebar.setOpaque(false);
btnShowSidebar.setAlignmentX(JComponent.RIGHT_ALIGNMENT);
btnShowSidebar.setBorder(new EmptyBorder(new Insets(2,2,2,2)));
// Add site manager toolbar
sidebar.setLayout(new GridLayout(2, 0));
sidebar.setAlignmentX(JComponent.RIGHT_ALIGNMENT);
sidebar.add(siteManagementPanel);
sidebar.add(new JScrollPane(layerManagerView));
mainPanel.add(sidebar, BorderLayout.EAST);
Main.statusBar = new StatusBar();
Main.statusBar.setCanvasTabbedPane(mCanvasTabbedPane);
mainPanel.add(Main.statusBar, BorderLayout.SOUTH);
mainPanel.setVisible(true);
}
....
....
}
I keep telling myself that this should be simple, and yet I'm completely lost. Let me start by saying that I'm new to NetBeans IDE, and that I am using it out of necessity. I don't really know much about it yet.
I have successfully designed my main window for my application. The right side of the application is essentially a large window into a three-dimensional space that visualizes certain transforms on data sets. I have searched through the palette and the palette manager and even tried to add the Canvas3D component to the palette manually from a JAR, but I still can't get it.
I would really like to be able to drag and drop this component into my application, and intuitively, it seems possible. I'm on Mac OS X; the output from my About NetBeans tells more.
Product Version: NetBeans IDE 6.7 (Build 200906241340)
Java: 1.5.0_19; Java HotSpot(TM) Client VM 1.5.0_19-137
System: Mac OS X version 10.5.7 running on i386; MacRoman; en_US (nb)
Userdir: /Users/dremelofdeath/.netbeans/6.7
Thanks in advance for helping me out -- I really appreciate it.
The Canvas3D is a heavyweight component meaning it uses a native peer component to hook into DirectX or OpenGL so probably this kind of component is not available for drag and drop. Though you could try extending a JPanel.
You can setup the layout manually quite easily using a BoderLayout.
MyFrame extends JFrame {
etc...
Container container = getContentPane();
container.setName("main.container");
container.setLayout(new BorderLayout());
container.add(new MyCanvasPanel(), BorderLayout.CENTER);
}
// this could probably be added to the palete
public class MyCanvasPanel extends JPanel {
SimpleUniverse su;
Canvas3D canvas3D;
public MyCanvasPanel() {
canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
add("Center", canvas3D);
su = new SimpleUniverse(canvas3D);
}
}
Complete beginner guide:
Add a java.awt.Container to the JFrame. (Choose Beans\java.awt.Container).
Let the name of that container be canvasContainer.
Add a public variable to the class. (I assume the class name is MyJFrame)
public Canvas3D canvas3D;
The construction of the frame class is as follows:
public MyJFrame() {
initComponents();
}
Edit it as follows:
public MyJFrame() {
initComponents();
canvas3D = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
canvasContainer.add(canvas3D, "Center");
canvas3D.setSize(canvasContainer.getWidth(), canvasContainer.getHeight());
}
Add a listener to the Container when it is resized: (Often when the window is resized)
Choose the container \ Properties \ Events \ componentResized \ canvasContainerComponentResized
Type the following code:
if (canvas3D!=null)
canvas3D.setSize(canvasContainer.getWidth(), canvasContainer.getHeight());
I would like to find the window ID of my SWT program.
I start up my SWT shell in the standard way. How do I then find the ID of the window that's been created? The program is executing on Fedora 10 using the Compiz-Fusion window manager (if that makes a difference).
Code to help explain what I mean:
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell();
// find window ID here??
shell.open();
while (!shell.isDisposed()) {
if(!display.readAndDispatch()) {
display.sleep();
}
}
}
Update 6 Mar 2009
After looking at and trying out a whole range of things (thanks to VonC for the suggestions below), I came across something that's worked so far. It's supremely dodgy but at least allows me to get on with some other work for the moment.
The ID returned from Control.embeddedHandle is close to the window ID. It's different by a predictable offset. So my code is:
public static void main(String[] args) {
...
Shell shell = new shell(display, SWT.NONE);
Composite e = new Composite(shell, SWT.EMBEDDED);
long windowID = e.embeddedHandle - WINDOW_ID_MAGIC_NUMBER;
e.dispose();
....
WINDOW_ID_MAGIC_NUMBER is 5+(number of widgets added to shell before the embedded composite).
It seems reliable on my system so far. I have yet to see if it falls over in a different environment.
If you create a Composite with the style SWT.EMBEDDED style, then under SWT/GTK+ Composite.embeddedHandle will be an X window ID you can use for parenting an XEMBED child.
Composite embed = new Composite(shell, SWT.EMBEDDED);
System.out.println ("X window ID: " + embed.embeddedHandle);
int hwndChild = OS.GetWindow ( c.handle, OS.GW_CHILD);
This supports embedding using the XEMBED protocol.
This is similar to the JNI code used to get the window ID from its handle
GtkWidget *widget = (GtkWidget *) handle;
GdkWindow *window = widget->window;
xwinid = GDK_WINDOW_XWINDOW(window);
Example of code here.
Example of class using OS:
org.eclipse.swt.widgets.Tree, org.eclipse.swt.widgets.CoolItem,
OS I can find is indeed org.eclipse.swt.internal.win32.OS, not gtk, and it is not a perfect solution because you would access an internal package, but that can give you an idea where to look.
In your case, org.eclipse.swt.internal.gtk.OS is the right class, and you should look in Tree or CoolItem sources how they are using the GetWindow function.
Some other function need to be called in GTK, like may be gtk_container_get_children(int container);
It is said in an answer to the message I was referring at the beginning
If you need the X window, there's no way to do this from the public SWT API (even going through internals), and furthermore even if there was a way I don't think you could guarantee it for all controls. I'm not sure if this works but the closest you could get might be to:
make Control.fixedHandle public
Use OS.GTK_WIDGET_WINDOW (control.fixedHandle) to get a GdkWindow
Use OS.gdk_x11_drawable_get_xid (gdkWindow) to translate that to an X window
I guess the other way might be to take Control.handle, and then call GTK_WIDGET_WINDOW() on it, or if that's null keep calling it on its parents until you find one with a GdkWindow, and then translate that to an X window.
The difficulty here is that SWT talks to GTK+, which talks to GDK, which then talks to X. So, there's three layers between you and the X window.
Not sure if this still matters to you, 7 years later :-), but this works for me:
private static long getWindowIdFromShell(Shell shell) {
long handle = shell.handle;
long topWidget = OS._gtk_widget_get_toplevel(handle);
long topWindow = OS._gtk_widget_get_window(topWidget);
long topXid = OS._gdk_x11_window_get_xid(topWindow);
return topXid;
}
In particular, the "get_toplevel" step is what jumps to the root widget/window, and so means you don't need the "minus magic window offset" hack (which I was initially stuck doing as well).