首页 > 解决方案 > 如何在 Linux 上使用 Java 将 GEdit 置于前端

问题描述

我们基于 Java/SWT 的应用程序可以启动用户可编辑的第三方应用程序,例如编辑器。例如,在 Linux(CentOS 7、Gnome 3.28.2)上,当启动“gedit”时,它可以正常打开,但在我们的应用程序窗口后面。奇怪的是,当从终端(gnome-terminal)启动“gedit”时,GEdit 出现在最前面的窗口中。

如何告诉“gedit”(或其他)作为最前面的应用程序启动?

更新: 当我从 IDE (IDEA) 启动我的 Java 应用程序时,它按预期工作(Gedit 在前面)。如果我从 shell 脚本启动我的应用程序,它会按预期工作。如果我从指向 shell 脚本的 .desktop 文件启动应用程序,Gedit 不仅会打开文件,还会显示有关准备就绪的通知。也许这会以某种方式混淆应用程序窗口的 z 顺序?或者它取决于环境变量:如果从 .desktop 文件启动,环境变量DESKTOP_STARTUP_ID, GIO_LAUNCHED_DESKTOP_FILE,GIO_LAUNCHED_DESKTOP_FILE_PID额外可用并且HISTCONTROL设置为代替ignoredups,ignorespace代替,设置为代替。SHLVL24TERMdumpxterm-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 次访问是必不可少的。

标签: linuxxorg

解决方案


现在可以做出许多假设(例如.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

.desktop 文件

指向 shell 文件的 .desktop 文件如下所示:

[Desktop Entry]
Type=Application
Terminal=false
Name=Opener
Icon=utilities-terminal
Exec='/home/stephan/Documents/opener.sh'
Categories=Application;

结果

通过单击打开 gedit按钮,gedit 在所有其他窗口中按预期启动。

演示

测试是在 CentOS Linux 7 上完成的:

gnome-shell --version

给出输出:

GNOME Shell 3.28.3

gedit 演示


推荐阅读