Skip to content

Commit 72d3a2a

Browse files
author
Alexey Semenyuk
committed
8308349: missing working directory option for launcher when invoked from shortcuts
Reviewed-by: almatvee
1 parent 6927fc3 commit 72d3a2a

16 files changed

Lines changed: 344 additions & 100 deletions

File tree

src/jdk.jpackage/linux/classes/jdk/jpackage/internal/DesktopIntegration.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import javax.xml.stream.XMLStreamException;
4747
import javax.xml.stream.XMLStreamWriter;
4848
import jdk.jpackage.internal.model.FileAssociation;
49+
import jdk.jpackage.internal.model.LauncherShortcut;
4950
import jdk.jpackage.internal.model.LinuxLauncher;
5051
import jdk.jpackage.internal.model.LinuxPackage;
5152
import jdk.jpackage.internal.model.Package;
@@ -237,6 +238,23 @@ private Map<String, String> createDataForDesktopFile() {
237238
data.put("DEPLOY_BUNDLE_CATEGORY", pkg.menuGroupName());
238239
data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(
239240
installedLayout.launchersDirectory().resolve(launcher.executableNameWithSuffix()).toString()));
241+
data.put("STARTUP_DIRECTORY", launcher.shortcut()
242+
.flatMap(LauncherShortcut::startupDirectory)
243+
.map(startupDirectory -> {
244+
switch (startupDirectory) {
245+
case DEFAULT -> {
246+
return (Path)null;
247+
}
248+
case APP_DIR -> {
249+
return installedLayout.appDirectory();
250+
}
251+
default -> {
252+
throw new AssertionError();
253+
}
254+
}
255+
}).map(str -> {
256+
return "Path=" + str;
257+
}).orElse(null));
240258

241259
return data;
242260
}

src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxFromParams.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,12 +109,8 @@ private static LinuxPackage createLinuxDebPackage(
109109
static final BundlerParamInfo<LinuxPackage> DEB_PACKAGE = createPackageBundlerParam(
110110
LinuxFromParams::createLinuxDebPackage);
111111

112-
private static final BundlerParamInfo<Boolean> LINUX_SHORTCUT_HINT = new BundlerParamInfo<>(
113-
Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(),
114-
Boolean.class,
115-
params -> false,
116-
(s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)
117-
);
112+
private static final BundlerParamInfo<String> LINUX_SHORTCUT_HINT = createStringBundlerParam(
113+
Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId());
118114

119115
private static final BundlerParamInfo<String> LINUX_CATEGORY = createStringBundlerParam(
120116
Arguments.CLIOptions.LINUX_CATEGORY.getId());

src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/template.desktop

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Name=APPLICATION_NAME
33
Comment=APPLICATION_DESCRIPTION
44
Exec=APPLICATION_LAUNCHER
5+
STARTUP_DIRECTORY
56
Icon=APPLICATION_ICON
67
Terminal=false
78
Type=Application

src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.util.HashMap;
3838
import java.util.List;
3939
import java.util.Map;
40+
import java.util.Objects;
4041
import java.util.Optional;
4142
import java.util.Properties;
4243
import java.util.ResourceBundle;
@@ -348,16 +349,13 @@ public enum CLIOptions {
348349

349350
WIN_UPDATE_URL ("win-update-url", OptionCategories.PLATFORM_WIN),
350351

351-
WIN_MENU_HINT ("win-menu", OptionCategories.PLATFORM_WIN, () -> {
352-
setOptionValue("win-menu", true);
353-
}),
352+
WIN_MENU_HINT ("win-menu", OptionCategories.PLATFORM_WIN,
353+
createArgumentWithOptionalValueAction("win-menu")),
354354

355355
WIN_MENU_GROUP ("win-menu-group", OptionCategories.PLATFORM_WIN),
356356

357-
WIN_SHORTCUT_HINT ("win-shortcut",
358-
OptionCategories.PLATFORM_WIN, () -> {
359-
setOptionValue("win-shortcut", true);
360-
}),
357+
WIN_SHORTCUT_HINT ("win-shortcut", OptionCategories.PLATFORM_WIN,
358+
createArgumentWithOptionalValueAction("win-shortcut")),
361359

362360
WIN_SHORTCUT_PROMPT ("win-shortcut-prompt",
363361
OptionCategories.PLATFORM_WIN, () -> {
@@ -396,10 +394,8 @@ public enum CLIOptions {
396394
LINUX_PACKAGE_DEPENDENCIES ("linux-package-deps",
397395
OptionCategories.PLATFORM_LINUX),
398396

399-
LINUX_SHORTCUT_HINT ("linux-shortcut",
400-
OptionCategories.PLATFORM_LINUX, () -> {
401-
setOptionValue("linux-shortcut", true);
402-
}),
397+
LINUX_SHORTCUT_HINT ("linux-shortcut", OptionCategories.PLATFORM_LINUX,
398+
createArgumentWithOptionalValueAction("linux-shortcut")),
403399

404400
LINUX_MENU_GROUP ("linux-menu-group", OptionCategories.PLATFORM_LINUX);
405401

@@ -478,9 +474,32 @@ private static void nextArg() {
478474
context().pos++;
479475
}
480476

477+
private static void prevArg() {
478+
Objects.checkIndex(context().pos, context().argList.size());
479+
context().pos--;
480+
}
481+
481482
private static boolean hasNextArg() {
482483
return context().pos < context().argList.size();
483484
}
485+
486+
private static Runnable createArgumentWithOptionalValueAction(String option) {
487+
Objects.requireNonNull(option);
488+
return () -> {
489+
nextArg();
490+
if (hasNextArg()) {
491+
var value = getArg();
492+
if (value.startsWith("-")) {
493+
prevArg();
494+
setOptionValue(option, true);
495+
} else {
496+
setOptionValue(option, value);
497+
}
498+
} else {
499+
setOptionValue(option, true);
500+
}
501+
};
502+
}
484503
}
485504

486505
enum OptionCategories {

src/jdk.jpackage/share/classes/jdk/jpackage/internal/FromParams.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
5353
import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage;
5454
import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller;
55+
import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction;
5556

5657
import java.io.IOException;
5758
import java.nio.file.Path;
@@ -69,6 +70,7 @@
6970
import jdk.jpackage.internal.model.LauncherShortcut;
7071
import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory;
7172
import jdk.jpackage.internal.model.PackageType;
73+
import jdk.jpackage.internal.model.ParseUtils;
7274
import jdk.jpackage.internal.model.RuntimeLayout;
7375
import jdk.jpackage.internal.util.function.ThrowingFunction;
7476

@@ -171,29 +173,31 @@ static Optional<jdk.jpackage.internal.model.Package> getCurrentPackage(Map<Strin
171173
}
172174

173175
static Optional<LauncherShortcut> findLauncherShortcut(
174-
BundlerParamInfo<Boolean> shortcutParam,
176+
BundlerParamInfo<String> shortcutParam,
175177
Map<String, ? super Object> mainParams,
176178
Map<String, ? super Object> launcherParams) {
177179

178-
Optional<Boolean> launcherValue;
180+
Optional<String> launcherValue;
179181
if (launcherParams == mainParams) {
180182
// The main launcher
181183
launcherValue = Optional.empty();
182184
} else {
183185
launcherValue = shortcutParam.findIn(launcherParams);
184186
}
185187

186-
return launcherValue.map(withShortcut -> {
187-
if (withShortcut) {
188-
return Optional.of(LauncherShortcutStartupDirectory.DEFAULT);
189-
} else {
190-
return Optional.<LauncherShortcutStartupDirectory>empty();
191-
}
192-
}).or(() -> {
193-
return shortcutParam.findIn(mainParams).map(_ -> {
194-
return Optional.of(LauncherShortcutStartupDirectory.DEFAULT);
195-
});
196-
}).map(LauncherShortcut::new);
188+
return launcherValue.map(ParseUtils::parseLauncherShortcutForAddLauncher).or(() -> {
189+
return Optional.ofNullable(mainParams.get(shortcutParam.getID())).map(toFunction(value -> {
190+
if (value instanceof Boolean) {
191+
return new LauncherShortcut(LauncherShortcutStartupDirectory.DEFAULT);
192+
} else {
193+
try {
194+
return ParseUtils.parseLauncherShortcutForMainLauncher((String)value);
195+
} catch (IllegalArgumentException ex) {
196+
throw I18N.buildConfigException("error.invalid-option-value", value, "--" + shortcutParam.getID()).create();
197+
}
198+
}
199+
}));
200+
});
197201
}
198202

199203
private static ApplicationLaunchers createLaunchers(

src/jdk.jpackage/share/classes/jdk/jpackage/internal/model/LauncherShortcutStartupDirectory.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ public enum LauncherShortcutStartupDirectory {
4141
* On Linux, it indicates that a shortcut doesn't have the startup directory
4242
* configured explicitly.
4343
*/
44-
DEFAULT("true");
44+
DEFAULT("true"),
45+
46+
/**
47+
* The 'app' directory in the installed application app image. This is the
48+
* directory that is referenced with {@link ApplicationLayout#appDirectory()}
49+
* method.
50+
*/
51+
APP_DIR("app-dir");
4552

4653
LauncherShortcutStartupDirectory(String stringValue) {
4754
this.stringValue = Objects.requireNonNull(stringValue);
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
package jdk.jpackage.internal.model;
26+
27+
import java.util.Objects;
28+
import java.util.Optional;
29+
import java.util.stream.Stream;
30+
31+
/**
32+
* Collection of functions to create instances of types defined in this package from strings.
33+
*/
34+
public final class ParseUtils {
35+
36+
private ParseUtils() {
37+
}
38+
39+
public static LauncherShortcut parseLauncherShortcutForMainLauncher(String str) {
40+
return parse(str, LauncherShortcutStartupDirectory.APP_DIR).map(LauncherShortcut::new).orElseThrow(IllegalArgumentException::new);
41+
}
42+
43+
public static LauncherShortcut parseLauncherShortcutForAddLauncher(String str) {
44+
return parse(str, LauncherShortcutStartupDirectory.values()).map(LauncherShortcut::new).orElseGet(() -> {
45+
if (Boolean.valueOf(str)) {
46+
return new LauncherShortcut(LauncherShortcutStartupDirectory.DEFAULT);
47+
} else {
48+
return new LauncherShortcut();
49+
}
50+
});
51+
}
52+
53+
private static Optional<LauncherShortcutStartupDirectory> parse(String str, LauncherShortcutStartupDirectory... recognizedValues) {
54+
Objects.requireNonNull(str);
55+
return Stream.of(recognizedValues).filter(v -> {
56+
return str.equals(v.asStringValue());
57+
}).findFirst();
58+
}
59+
}

src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ error.invalid-app-image=Error: app-image dir "{0}" generated by another jpackage
8282

8383
error.invalid-install-dir=Invalid installation directory "{0}"
8484

85+
error.invalid-option-value=Invalid value "{0}" of option {1}
86+
8587
MSG_BundlerFailed=Error: Bundler "{1}" ({0}) failed to produce a package
8688
MSG_BundlerConfigException=Bundler {0} skipped because of a configuration problem: {1} \n\
8789
Advice to fix: {2}

src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinFromParams.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,10 @@ private static WinMsiPackage createWinMsiPackage(Map<String, ? super Object> par
105105
static final BundlerParamInfo<WinMsiPackage> MSI_PACKAGE = createPackageBundlerParam(
106106
WinFromParams::createWinMsiPackage);
107107

108-
private static final BundlerParamInfo<Boolean> WIN_MENU_HINT = createBooleanBundlerParam(
108+
private static final BundlerParamInfo<String> WIN_MENU_HINT = createStringBundlerParam(
109109
Arguments.CLIOptions.WIN_MENU_HINT.getId());
110110

111-
private static final BundlerParamInfo<Boolean> WIN_SHORTCUT_HINT = createBooleanBundlerParam(
111+
private static final BundlerParamInfo<String> WIN_SHORTCUT_HINT = createStringBundlerParam(
112112
Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId());
113113

114114
public static final BundlerParamInfo<Boolean> CONSOLE_HINT = createBooleanBundlerParam(

src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WixAppImageFragmentBuilder.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,9 @@ private void addShortcutComponentGroup(XMLStreamWriter xml) throws
474474
case DEFAULT -> {
475475
return INSTALLDIR;
476476
}
477+
case APP_DIR -> {
478+
return installedAppImage.appDirectory();
479+
}
477480
default -> {
478481
throw new AssertionError();
479482
}

0 commit comments

Comments
 (0)