如何在 Linux 上使用 Java 将 GEdit 置于最前面
How to bring GEdit to front using Java on Linux
我们的 Java/SWT-based 应用程序可以启动用户可编辑的第三方应用程序,例如编辑。例如,在 Linux(CentOS 7、Gnome 3.28.2)上,当启动 "gedit" 时,它可以正常打开,但落后于我们应用程序的 window。奇怪的是,当从终端 (gnome-terminal
) 启动 "gedit " 时,GEdit 出现在最前面 window.
如何告诉 "gedit"(或其他人)作为最前面的应用程序启动?
更新:
当我从 IDE (IDEA) 启动我的 Java-应用程序时,它按预期工作(Gedit 在前面)。如果我从 shell 脚本启动我的应用程序,它会按预期工作。如果我从指向 shell-脚本的 .desktop 文件启动应用程序,Gedit 不仅会打开文件 ,还会显示准备就绪的通知 。也许这会以某种方式混淆应用程序的 z 顺序 windows?或者它取决于环境变量:如果从 .desktop 文件启动,环境变量 DESKTOP_STARTUP_ID
、GIO_LAUNCHED_DESKTOP_FILE
、GIO_LAUNCHED_DESKTOP_FILE_PID
额外可用并且 HISTCONTROL
设置为 ignoredups
而不是 ignorespace
,SHLVL
是 2
而不是 4
,TERM
被设置为 dump
而不是 xterm-256color
。
根据 Stephan Schlecht 的代码,我发现以下 Java 代码应该重现问题:
import java.io.*;
import java.util.*;
import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public class EditorOpener {
public static void main(String[] args) {
final Map<String, String> getenv = System.getenv();
System.out.println(getenv);
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(500, 200);
shell.setText("Editor Opener");
shell.setLayout(new RowLayout());
final Button button = new Button(shell, SWT.PUSH);
button.setText("open gedit");
button.addListener(SWT.Selection, event -> new Thread(() -> {
final ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("/usr/bin/gedit");
final Map<String, String> environment = processBuilder.environment();
System.out.println(environment);
try {
final Process process = processBuilder.start();
process.waitFor();
}
catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}).start());
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
环境变量的2次访问必不可少
有这个实用程序 wmctrl 可以轻松地做你想做的事。
对于您的用例,您将使用 wmctrl -a "gedit"
或类似的东西。来自手册页:
-a
Switch to the desktop containing the window <WIN>, raise the window, and give it focus.
或者,您可以将程序最小化并在 gedit
完成后再次恢复它。
现在可以做出许多假设(例如 the.desktop 文件的内容),但最好有一个关于它如何工作的分步指南,例如像这样:
测试程序
此 SWT 程序通过 Runtime.getRuntime().exec 启动 'gedit'。
import java.io.IOException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class EditorOpener {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(500, 200);
shell.setText("Editor Opener");
shell.setLayout(new RowLayout());
final Button button = new Button(shell, SWT.PUSH);
button.setText("open gedit");
button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent event) {
String[] cmdArray = new String[] { "/usr/bin/gedit" };
try {
Runtime.getRuntime().exec(cmdArray);
}
catch(IOException ex) {
ex.printStackTrace();
}
}
public void widgetDefaultSelected(SelectionEvent event) {
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
调用Java程序
Java 程序是从如下所示的 shell 脚本调用的:
#!/usr/bin/bash
java -cp /path/to/swt.jar:/path/to/classes EditorOpener
.桌面文件
指向 shell 文件的 .desktop 文件如下所示:
[Desktop Entry]
Type=Application
Terminal=false
Name=Opener
Icon=utilities-terminal
Exec='/home/stephan/Documents/opener.sh'
Categories=Application;
结果
通过单击 open gedit 按钮,gedit 将按预期启动,高于所有其他 windows。
演示
测试是在CentOS上完成的Linux 7:
gnome-shell --version
给出输出:
GNOME Shell 3.28.3
原因是我们的 .desktop
文件包含行
StartupNotify=true
StartupWMClass=<main-class>
删除第一行会使问题消失。
我们的 Java/SWT-based 应用程序可以启动用户可编辑的第三方应用程序,例如编辑。例如,在 Linux(CentOS 7、Gnome 3.28.2)上,当启动 "gedit" 时,它可以正常打开,但落后于我们应用程序的 window。奇怪的是,当从终端 (gnome-terminal
) 启动 "gedit " 时,GEdit 出现在最前面 window.
如何告诉 "gedit"(或其他人)作为最前面的应用程序启动?
更新:
当我从 IDE (IDEA) 启动我的 Java-应用程序时,它按预期工作(Gedit 在前面)。如果我从 shell 脚本启动我的应用程序,它会按预期工作。如果我从指向 shell-脚本的 .desktop 文件启动应用程序,Gedit 不仅会打开文件 ,还会显示准备就绪的通知 。也许这会以某种方式混淆应用程序的 z 顺序 windows?或者它取决于环境变量:如果从 .desktop 文件启动,环境变量 DESKTOP_STARTUP_ID
、GIO_LAUNCHED_DESKTOP_FILE
、GIO_LAUNCHED_DESKTOP_FILE_PID
额外可用并且 HISTCONTROL
设置为 ignoredups
而不是 ignorespace
,SHLVL
是 2
而不是 4
,TERM
被设置为 dump
而不是 xterm-256color
。
根据 Stephan Schlecht 的代码,我发现以下 Java 代码应该重现问题:
import java.io.*;
import java.util.*;
import org.eclipse.swt.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
public class EditorOpener {
public static void main(String[] args) {
final Map<String, String> getenv = System.getenv();
System.out.println(getenv);
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(500, 200);
shell.setText("Editor Opener");
shell.setLayout(new RowLayout());
final Button button = new Button(shell, SWT.PUSH);
button.setText("open gedit");
button.addListener(SWT.Selection, event -> new Thread(() -> {
final ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("/usr/bin/gedit");
final Map<String, String> environment = processBuilder.environment();
System.out.println(environment);
try {
final Process process = processBuilder.start();
process.waitFor();
}
catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}).start());
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
环境变量的2次访问必不可少
有这个实用程序 wmctrl 可以轻松地做你想做的事。
对于您的用例,您将使用 wmctrl -a "gedit"
或类似的东西。来自手册页:
-a
Switch to the desktop containing the window <WIN>, raise the window, and give it focus.
或者,您可以将程序最小化并在 gedit
完成后再次恢复它。
现在可以做出许多假设(例如 the.desktop 文件的内容),但最好有一个关于它如何工作的分步指南,例如像这样:
测试程序
此 SWT 程序通过 Runtime.getRuntime().exec 启动 'gedit'。
import java.io.IOException;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
public class EditorOpener {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(500, 200);
shell.setText("Editor Opener");
shell.setLayout(new RowLayout());
final Button button = new Button(shell, SWT.PUSH);
button.setText("open gedit");
button.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent event) {
String[] cmdArray = new String[] { "/usr/bin/gedit" };
try {
Runtime.getRuntime().exec(cmdArray);
}
catch(IOException ex) {
ex.printStackTrace();
}
}
public void widgetDefaultSelected(SelectionEvent event) {
}
});
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
调用Java程序
Java 程序是从如下所示的 shell 脚本调用的:
#!/usr/bin/bash
java -cp /path/to/swt.jar:/path/to/classes EditorOpener
.桌面文件
指向 shell 文件的 .desktop 文件如下所示:
[Desktop Entry]
Type=Application
Terminal=false
Name=Opener
Icon=utilities-terminal
Exec='/home/stephan/Documents/opener.sh'
Categories=Application;
结果
通过单击 open gedit 按钮,gedit 将按预期启动,高于所有其他 windows。
演示
测试是在CentOS上完成的Linux 7:
gnome-shell --version
给出输出:
GNOME Shell 3.28.3
原因是我们的 .desktop
文件包含行
StartupNotify=true
StartupWMClass=<main-class>
删除第一行会使问题消失。