When your user launches your RCP without having any project open, he or she will eventually see a “welcome screen” looking similar to this:

How can you customize this screen? There are multiple options, from adding extra “tabs” similar to Projects or Customize, to hiding unwanted tabs, to replacing the screen completely with your own implementation.

In this post I want focus on removing unwanted tabs, simplifying the screen to look like this:

The architecture of the welcome screen is such that each tab is contributed by an extension to an extension point named com.intellij.welcomeTabFactory.

The predefined “tab factories” are listed in the file named META-INF/PlatformExtensions.xml contained in lib/platform-impl.jar:

<welcomeTabFactory id="ProjectsWelcomeTab"
  implementation="com.intellij.openapi.wm.impl.welcomeScreen.ProjectsTabFactory"/>
<welcomeTabFactory id="CustomizeWelcomeTab"
  implementation="com.intellij.openapi.wm.impl.welcomeScreen.CustomizeTabFactory"
  order="after ProjectsWelcomeTab"/>
<welcomeTabFactory id="PluginsWelcomeTab"
  implementation="com.intellij.openapi.wm.impl.welcomeScreen.PluginsTabFactory"
  order="after CustomizeWelcomeTab"/>
<welcomeTabFactory id="LearnIdeWelcomeTab"
  implementation="com.intellij.openapi.wm.impl.welcomeScreen.LearnIdeTabFactory"
  order="after PluginsWelcomeTab"/>

As is the case with many extensible systems, removing unwanted extensions is more difficult than adding new ones. While new extensions can be contributed by a plugin, to remove an existing extension we have to modify the file and remove the unwanted lines. The exact way to do this will depend on which tool you use to build your RCP, and in the rest of this email I will describe the way I would approach this task.

Rather than dig deep into XML processing code, I found a nice little library called xml-patch that can be used from Ant or Gradle to patch an XML file according to a declarative specification. DSLs! Yay!

For our case, the specification would look like this:

<diff>
    <remove sel="idea-plugin/extensions/welcomeTabFactory[@id='CustomizeWelcomeTab']"
            ws="after"/>
    <remove sel="idea-plugin/extensions/welcomeTabFactory[@id='PluginsWelcomeTab']" 
            ws="after"/>
    <remove sel="idea-plugin/extensions/welcomeTabFactory[@id='LearnIdeWelcomeTab']"
            ws="after"/>
</diff>

And this is how it could be used from a Gradle/Kotlin script to patch build/mps/lib/platform-impl.jar, putting the result into build/patched/platform-impl.jar:

import com.github.dnault.xmlpatch.filter.XmlPatch

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("com.github.dnault:xml-patch:0.3.1")
    }
}

tasks.register<Zip>("patchPlatformImplJar") {
    destinationDirectory.value(layout.buildDirectory.dir("patched"))
    archiveFileName.set("platform-impl.jar")
    from(zipTree("$buildDir/mps/lib/platform-impl.jar"))

    filesMatching("META-INF/PlatformExtensions.xml") {
        filter(XmlPatch::class,
            "patch" to "$projectDir/patches/patch-platform-extensions.xml")
    }
}

The script assumes that the patch XML file above is located in patches/patch-platform-extensions.xml in the project directory. With some more file manipulation (that I will leave as an exercise to the reader) we can replace the original platform-impl.jar in our RCP with the patched one, and enjoy the slimmed-down welcome screen.