Bug 234252 - [RCP] Secret magic required for images for project
Summary: [RCP] Secret magic required for images for project
Status: CLOSED WONTFIX
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 3.4   Edit
Hardware: All All
: P3 major with 3 votes (vote)
Target Milestone: ---   Edit
Assignee: Francis Upton IV CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks: 186891
  Show dependency tree
 
Reported: 2008-05-27 17:18 EDT by Francis Upton IV CLA
Modified: 2019-11-14 03:28 EST (History)
9 users (show)

See Also:
bokowski: review+


Attachments
Patch to declare images in the correct place (5.84 KB, patch)
2008-08-25 16:52 EDT, Francis Upton IV CLA
no flags Details | Diff
Additional patch to handle not starting on the UI thread (1.10 KB, patch)
2008-08-26 04:50 EDT, Francis Upton IV CLA
no flags Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Francis Upton IV CLA 2008-05-27 17:18:55 EDT
Here is the description of how to fix it.  This question gets asked over and over in the newsgroups:

http://dev.eclipse.org/newslists/news.eclipse.platform.rcp/msg24120.html

Should be a better way.

See also bug 221977 for other magic required to make things work.
Comment 1 Francis Upton IV CLA 2008-06-10 23:16:14 EDT
I filed this a while ago about the project icons, and then I discovered some more.  For example the SaveAs dialog won't work because the image is missing.  The problem is about half the images are loaded in the WorkbenchImages class and these are available to RCP applications that use the ui.ide plugin.  But the other half of the images are in the IDEWorkbenchAdvisor which is in the ui.ide.application plugin and not available for RCP.

The images that certainly need to move are:

		declareWorkbenchImage(ideBundle,
				IDEInternalWorkbenchImages.IMG_DLGBAN_SAVEAS_DLG, PATH_WIZBAN
						+ "saveas_wiz.png", false);	
		declareWorkbenchImage(ideBundle, IDE.SharedImages.IMG_OBJ_PROJECT,
				PATH_OBJECT + "prj_obj.gif", true);
		declareWorkbenchImage(ideBundle,
				IDE.SharedImages.IMG_OBJ_PROJECT_CLOSED, PATH_OBJECT
						+ "cprj_obj.gif", true);

However there are probably others; anything in the ui.ide plugin should work fine without using the ui.ide.application plugin.

This is important enough to fix in 3.4.1, as it wastes a lot of time for RCP developers.

My feeling is we should just move all of the images to WorkbenchImages (since the files are in the ui.ide plugin to begin with).  It won't cause any performance penalty for the IDE case, and I bet that declaring another 30 or so images for RCP people will not get them upset.

I'm happy to fix this however you decide.
Comment 2 Boris Bokowski CLA 2008-06-11 09:23:21 EDT
(In reply to comment #1)
> My feeling is we should just move all of the images to WorkbenchImages (since
> the files are in the ui.ide plugin to begin with).

WorkbenchImages is in org.eclipse.ui.workbench, so we cannot just move the declareImage calls to WorkbenchImages if the image files are in org.eclipse.ui.ide.

I don't know how we can fix this without introducing new API.
Comment 3 Francis Upton IV CLA 2008-06-11 09:30:35 EDT
(In reply to comment #2)
> (In reply to comment #1)
> > My feeling is we should just move all of the images to WorkbenchImages (since
> > the files are in the ui.ide plugin to begin with).
> 
> WorkbenchImages is in org.eclipse.ui.workbench, so we cannot just move the
> declareImage calls to WorkbenchImages if the image files are in
> org.eclipse.ui.ide.
> 
> I don't know how we can fix this without introducing new API.
> 

But the actual image files are in ui.ide (unless they are somewhere else as well that I don't know about).  Is there some case where we support using ui.workbench without ui.ide?  As a practical matter you need ui.ide to do most things for RCP (certainly for resources).  Why couldn't we just move the calls to declare the images over to the WorkbenchImages class?  (Sorry if I'm being thick here)
Comment 4 Boris Bokowski CLA 2008-06-11 10:44:47 EDT
(In reply to comment #3)
> ... Is there some case where we support using
> ui.workbench without ui.ide?

Yes, definitely! Not all RCP apps use resources. The whole point of the RCP split in 3.0 was to rid the base RCP feature of everything that smelled like IDE, such as core.resources, ui.ide etc.
Comment 5 Francis Upton IV CLA 2008-06-11 10:52:54 EDT
(In reply to comment #4)

> Yes, definitely! Not all RCP apps use resources. The whole point of the RCP
> split in 3.0 was to rid the base RCP feature of everything that smelled like
> IDE, such as core.resources, ui.ide etc.
> 

Still, since the images (loaded currently in WorkbenchImages) are defined in ui.ide, they are not going to be available to RCP apps who don't include that package in any case (unless these images are also somewhere else, but I did not see that).  So I don't think there is harm (and there is substantial benefit) to do what I propose.


Comment 6 Francis Upton IV CLA 2008-06-12 09:08:41 EDT
This is a subset of bug 186891, but not a duplicate as I would prefer this be kept separate.
Comment 7 Francis Upton IV CLA 2008-08-25 16:52:16 EDT
Created attachment 110842 [details]
Patch to declare images in the correct place

After looking at this more, I realized the real problem.

There are some images, declared in IDE.SharedImages (in ui.ide) that are not loaded if you just include ui.ide.  This is because they are loaded in IDEWorkbenchAdvisor which is in ui.ide.application, and of course started only when you are running the IDE application.

This is clearly a bug, the images in IDE.SharedImages should be available if you use ui.ide and not ui.ide.application.

This patch splits those images from the IDEWorkbenchAdvisor startup and addes startup code to declare the ui.ide images in the correct place.

This is an important bug because RCP developers who use resources and any of our navigators always have problems with the project icons which don't correctly appear.  This corrects that.

I tested this with an RCP application (that previously had to explicitly declare the images) as well as the IDE.
Comment 8 Francis Upton IV CLA 2008-08-25 16:54:42 EDT
Boris, can you have a look at this patch today or early tomorrow, as I would like to get it into 3.4.1.  If there is a better place to put the startup code for the ui.ide plugin, I will revise the patch.  Please look at the previous comment to this as it really explains the issue.
Comment 9 Francis Upton IV CLA 2008-08-25 18:28:42 EDT
Released to HEAD (3.5M2) and R3_4_maintenance (3.4.1)
Comment 10 Francis Upton IV CLA 2008-08-26 04:50:05 EDT
Created attachment 110907 [details]
Additional patch to handle not starting on the UI thread

Dani ran into this problem.
Comment 11 Francis Upton IV CLA 2008-08-26 04:54:04 EDT
(from Dani)

Hi guys,

the fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=234252 is not OK
as it assumes that start(BundleContext) is called in the UI thread.
Unfortunately this is not true. The bundle is started the very first time a
class from it gets loaded. This can happen because some non-UI job or
thread that references a class from the bundle is running . With the fix
this will now result in an invalid thread access.

Dani
Comment 12 Dani Megert CLA 2008-08-26 05:16:57 EDT
start() should be lightweight and fast which is not the case when you post to the UI thread. Clients might only do some non-UI stuff (aka headless) which starts the IDE bundle because they use one of its classes but never do something in the UI. In fact the UI/workbench might not never be loaded (PlatformUI.isWorkbenchRunning() is false). We also had to protect JDT UI against such situations.

In case of doubt simply check bugzilla for various instances where people broke Eclipse start up by putting UI code into the bundle/plugin start method. A prominent case where this can happen is when core starts the auto-build job faster than the workbench gets started.
Comment 13 Boris Bokowski CLA 2008-08-26 08:26:47 EDT
Dani, do you have a stack trace for the invalid thread access? I'd like to know where excatly we are accessing SWT (I thought the code is only creating a couple of ImageDescriptors and remembering them in a map).
Comment 14 Dani Megert CLA 2008-08-26 08:41:23 EDT
Well, you run into the problem that others did as well: the image registry - even though only storing descriptors at that point - wants a display. So, while in general you get an invalid thread access when accessing UI stuff, you actually get an NPE in this scenario.

Thread (Suspended (exception NullPointerException))	
	owns: DefaultClassLoader  (id=47)	
	JFaceResources.getResources(Display) line: 207	
	ImageRegistry.<init>(Display) line: 155	
	ImageRegistry.<init>() line: 126	
	WorkbenchImages.initializeImageRegistry() line: 570	
	WorkbenchImages.getDescriptors() line: 471	
	WorkbenchImages.declareImage(String, ImageDescriptor, boolean) line: 458	
	IDEWorkbenchPlugin.declareWorkbenchImage(Bundle, String, String, boolean) line: 412	
	IDEWorkbenchPlugin.declareWorkbenchImages() line: 381	
	IDEWorkbenchPlugin.start(BundleContext) line: 360	
	BundleContextImpl$2.run() line: 1009	
	AccessController.doPrivileged(PrivilegedExceptionAction<T>) line: not available [native method]	
	BundleContextImpl.startActivator(BundleActivator) line: 1003	
	BundleContextImpl.start() line: 984	
	BundleHost.startWorker(int) line: 344	
	BundleHost(AbstractBundle).start(int) line: 267	
	SecureAction.start(Bundle, int) line: 400	
	EclipseLazyStarter.postFindLocalClass(String, Class, ClasspathManager) line: 111	
	ClasspathManager.findLocalClass(String) line: 427	
	DefaultClassLoader.findLocalClass(String) line: 193	
	BundleLoader.findLocalClass(String) line: 368	
	SingleSourcePackage.loadClass(String) line: 33	
	BundleLoader.findClassInternal(String, boolean, ClassLoader) line: 441	
	BundleLoader.findClass(String, boolean) line: 397	
	BundleLoader.findClass(String) line: 385	
	DefaultClassLoader.loadClass(String, boolean) line: 87	
	DefaultClassLoader(ClassLoader).loadClass(String) line: 251	
	DefaultClassLoader(ClassLoader).loadClassInternal(String) line: 319	
	IDEApplication.start(IApplicationContext) line: 114	
	EclipseAppHandle.run(Object) line: 193	
	EclipseAppLauncher.runApplication(Object) line: 110	
	EclipseAppLauncher.start(Object) line: 79	
	EclipseStarter.run(Object) line: 386	
	EclipseStarter.run(String[], Runnable) line: 179	
	NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]	
	NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39	
	DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25	
	Method.invoke(Object, Object...) line: 585	
	Main.invokeFramework(String[], URL[]) line: 549	
	Main.basicRun(String[]) line: 504	
	Main.run(String[]) line: 1236	
	Main.main(String[]) line: 1212	
Comment 15 Francis Upton IV CLA 2008-08-26 09:50:25 EDT
(In reply to comment #12)
> start() should be lightweight and fast which is not the case when you post to
> the UI thread. Clients might only do some non-UI stuff (aka headless) which
> starts the IDE bundle because they use one of its classes but never do
> something in the UI. In fact the UI/workbench might not never be loaded
> (PlatformUI.isWorkbenchRunning() is false). We also had to protect JDT UI
> against such situations.

Dani, what do you recommend we do here?  Is there a better place to load these images?  I can add a check for PlatformUI.isWorkbenchRunning() (I assume it would be set by the time the ui.ide bundle started).
Comment 16 Dani Megert CLA 2008-08-26 10:06:36 EDT
Checking whether the wb is running is a bad idea because if another thread starts the bundle then you will end up with no images.

Take a look at org.eclipse.jdt.internal.ui.JavaPluginImages.

Comment 17 Francis Upton IV CLA 2008-08-26 10:15:46 EDT
(In reply to comment #16)
> Checking whether the wb is running is a bad idea because if another thread
> starts the bundle then you will end up with no images.
Agreed
> 
> Take a look at org.eclipse.jdt.internal.ui.JavaPluginImages.
Ok, this does it all in the static initialization, but how is that better than doing it in start()?  I'm certainly happy to move it to be done in static initialization if that's the best answer.

Comment 18 Dani Megert CLA 2008-08-26 10:20:13 EDT
Two major differences:
1. it's done when the registry is really needed i.e. the class loaded
2. it does not crash when created in non-ui thread
Comment 19 Francis Upton IV CLA 2008-08-26 10:30:03 EDT
(In reply to comment #18)
> Two major differences:
> 1. it's done when the registry is really needed i.e. the class loaded
> 2. it does not crash when created in non-ui thread
> 
How are you sure that the static initializer is called on the UI thread?  It seems that the constructor you use of ImageRegistry() requires that it be run on the UI thread.  There must be something I don't understand here.
Comment 20 Dani Megert CLA 2008-08-26 10:53:00 EDT
>How are you sure that the static initializer is called on the UI thread?
We aren't. The code is written so that it can safely run in a non-UI thread. Take a closer look at the code (especially at fgAvoidSWTErrorMap).
Comment 21 Boris Bokowski CLA 2008-08-26 11:29:50 EDT
I don't see a simple solution to this problem. Let's back out of it for 3.4.1 and work on a solution for 3.5.

Thanks Dani for catching this!
Comment 22 Francis Upton IV CLA 2008-08-26 12:23:07 EDT
Backed out of R3_4_maintenance (3.4.1)
Comment 23 Francis Upton IV CLA 2008-08-27 01:25:16 EDT
I think a simple way to solve this, in a nice general way is to exploit the fact that all image access goes through the shared images object (SharedImages).  If this is the case, then the startup code can simply create a Runnable with the code to load the images, this Runnable can be given to the SharedImages so at the next image request, it can load all of the images.  I'm also assuming that image requests from the SharedImages must be run on the UI thread.  This mechanism could be used to simplify all image loading, for example the JavaPluginImages could be adapted to use this.

Are my assumptions about this correct?
Comment 24 Dani Megert CLA 2008-08-27 03:06:35 EDT
>Backed out of R3_4_maintenance (3.4.1)
Please also remove this from 3.5 until we have a working solution.
Comment 25 Dani Megert CLA 2008-08-27 05:01:51 EDT
I don't think you need a runnable and in fact it's not directly your patch that's not good but the underlying problem it surfaces: what you want to do on startup is to declare the image DESCRIPTORS using WorkbenchImages.declareImage(String, ImageDescriptor, boolean) - that's OK. Hence what we need to do is make that method safe when called from another thread i.e. allow to set and get descriptors from non-UI threads via WorkbenchImages and create the (shared) images when correctly requested via UI thread (as JavaPluginImages does). If WorkbenchImages would work that way, we would also not have seen:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=227721#c10
Comment 26 Francis Upton IV CLA 2008-08-27 09:34:04 EDT
Backed out of HEAD

(thanks Dani, I forgot about this)
Comment 27 Francis Upton IV CLA 2009-03-02 09:21:54 EST
Paul, I know there was some discussion of shared images at the last UI call.  Does it have any bearing on this issue? I would like to try and get this resolved for M6 if possible.
Comment 28 Paul Webster CLA 2009-03-02 09:34:41 EST
(In reply to comment #27)
> Paul, I know there was some discussion of shared images at the last UI call. 
> Does it have any bearing on this issue? I would like to try and get this
> resolved for M6 if possible.

We were looking into bug 246224, how to declaratively access shared images.

PW


Comment 29 Simon Chemouil CLA 2009-09-21 04:54:35 EDT
+1
Comment 30 John Bodkin CLA 2011-06-09 16:24:05 EDT
I just spent a few days trying to figure out why the Navigator view and the Project explorer view project icons were not showing. I followed instructions in this blog post to get them working in 3.6:
http://francisu.wordpress.com/2008/05/27/magic-required-to-use-the-common-navigator-in-an-rcp-application/

Just wanted to provide a quicker way to find a workaround for this item by adding this comment.
Comment 31 Lars Vogel CLA 2019-11-14 03:28:10 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

If the bug is still relevant, please remove the "stalebug" whiteboard tag.