From f160b07bf44de0a0ad2c4d97516fd310f557e535 Mon Sep 17 00:00:00 2001 From: rattatwinko Date: Wed, 27 May 2026 07:21:30 +0200 Subject: [PATCH] experimenting with sessions and stuff like that. Changes: + Login Panel + Some Kernel Booting stuff --- src/main/java/com/rdesk/Main.java | 98 +------ .../com/rdesk/applications/system/Exit.java | 47 ++- .../applications/system/login/Handler.java | 126 +++++++++ .../applications/system/login/Login.java | 267 ++++++++++++++++++ .../applications/system/login/UserRecord.java | 10 + src/main/java/com/rdesk/kernel/BootMgr.java | 40 +++ src/main/java/com/rdesk/kernel/BootProc.java | 109 +++++++ src/main/java/com/rdesk/kernel/Kernel.java | 8 + 8 files changed, 603 insertions(+), 102 deletions(-) create mode 100644 src/main/java/com/rdesk/applications/system/login/Handler.java create mode 100644 src/main/java/com/rdesk/applications/system/login/Login.java create mode 100644 src/main/java/com/rdesk/applications/system/login/UserRecord.java create mode 100644 src/main/java/com/rdesk/kernel/BootMgr.java create mode 100644 src/main/java/com/rdesk/kernel/BootProc.java diff --git a/src/main/java/com/rdesk/Main.java b/src/main/java/com/rdesk/Main.java index 7927f29..6f191dc 100644 --- a/src/main/java/com/rdesk/Main.java +++ b/src/main/java/com/rdesk/Main.java @@ -1,103 +1,9 @@ package com.rdesk; -import com.rdesk.applications.entertainment.comic.Xkcd; -import com.rdesk.applications.productivity.Calculator; -import com.rdesk.applications.productivity.browsing.TabbedBrowser; -import com.rdesk.applications.productivity.code.CodeDesk; -import com.rdesk.applications.system.Exit; -import com.rdesk.applications.productivity.Notes; -import com.rdesk.applications.system.TaskManager; -import com.rdesk.applications.system.filehaj.FileExplorerApp; -import com.rdesk.applications.system.rsys.KbChanger; -import com.rdesk.kernel.*; -import com.rdesk.kernel.launcher.AppLauncher; - -import javax.swing.*; +import com.rdesk.applications.system.login.Login; public class Main { - - private static final boolean RUN_IN_FS = false; - private static final boolean USE_SYSDEFAULT_LAF = false; - private static final boolean USE_FLATLAF = false; - private static final boolean loadSettingsKernelFlag = true; - public static void main(String[] args) { - SwingUtilities.invokeLater(Main::boot); - } - - private static void boot() { - Kernel kernel = Kernel.get(); - kernel.initSettings(loadSettingsKernelFlag); - kernel.boot(); - JFrame frame = new JFrame("rDesk"); - - frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - frame.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - kernel.shutdown(); - } - }); - - if (USE_FLATLAF) { - try { - UIManager.setLookAndFeel( - "com.formdev.flatlaf.themes.FlatMacLightLaf" - ); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - JOptionPane.showMessageDialog( - null, - ex.getMessage() + "@USE_FLATLAF" - ); - } - } - - if (USE_SYSDEFAULT_LAF) { - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - JOptionPane.showMessageDialog( - null, - ex.getMessage() + "@USE_SYSDEFAULT_LAF" - ); - } - } - - if (RUN_IN_FS) { - frame.setUndecorated(true); - frame.setExtendedState(JFrame.MAXIMIZED_BOTH); - } else { - frame.setSize(1200, 800); - frame.setLocationRelativeTo(null); - } - - JDesktopPane desktop = new JDesktopPane(); - kernel.windows().attachDesktop(desktop); - - AppLauncher launcher = new AppLauncher(kernel); - - registerSystemApps(launcher); - - JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, launcher, desktop); - split.setDividerSize(0); - split.setEnabled(false); - - frame.setContentPane(split); - frame.setVisible(true); - } - - private static void registerSystemApps(AppLauncher launcher) { - // productivity - launcher.addApp(new Notes(), "Productivity"); - launcher.addApp(new TabbedBrowser(), "Productivity"); - launcher.addApp(new CodeDesk(), "Productivity"); - launcher.addApp(new Calculator(), "Productivity"); - // entertainment - launcher.addApp(new Xkcd(), "Entertainment"); - // System apps - launcher.addApp(new Exit(), "System"); - launcher.addApp(new TaskManager(), "System"); - launcher.addApp(new FileExplorerApp(), "System"); - launcher.addApp(new KbChanger(), "System"); + Login.main(args); } } \ No newline at end of file diff --git a/src/main/java/com/rdesk/applications/system/Exit.java b/src/main/java/com/rdesk/applications/system/Exit.java index 4dc9fbb..b71f0db 100644 --- a/src/main/java/com/rdesk/applications/system/Exit.java +++ b/src/main/java/com/rdesk/applications/system/Exit.java @@ -1,11 +1,13 @@ package com.rdesk.applications.system; +import com.rdesk.applications.system.login.Login; import com.rdesk.kernel.DesktopApp; import com.rdesk.kernel.Kernel; import javax.swing.*; import java.awt.*; import java.io.IOException; +import java.awt.Window; public class Exit implements DesktopApp { @@ -22,7 +24,7 @@ public class Exit implements DesktopApp { @Override public JInternalFrame createWindow(Kernel kernel) { JInternalFrame frame = new JInternalFrame("System Controls", true, true); - frame.setSize(350, 180); + frame.setSize(420, 240); frame.setResizable(false); JPanel mainPanel = new JPanel(new GridBagLayout()); @@ -30,7 +32,7 @@ public class Exit implements DesktopApp { GridBagConstraints gbc = new GridBagConstraints(); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.fill = GridBagConstraints.HORIZONTAL; - gbc.insets = new Insets(5, 5, 5, 5); + gbc.insets = new Insets(6, 6, 6, 6); JLabel label = new JLabel("Choose an action:"); label.setFont(label.getFont().deriveFont(Font.BOLD)); @@ -38,8 +40,11 @@ public class Exit implements DesktopApp { JButton shutdownButton = new JButton("Shutdown rDesk"); JButton shutdownOS = new JButton("Shutdown Host OS"); + JButton logoffButton = new JButton("Log off"); + shutdownButton.setFocusPainted(false); shutdownButton.addActionListener(e -> confirmAndShutdown(kernel, frame)); + shutdownOS.setFocusPainted(false); shutdownOS.addActionListener(e -> { try { @@ -48,8 +53,38 @@ public class Exit implements DesktopApp { throw new RuntimeException(ex); } }); + + logoffButton.setFocusPainted(false); + + logoffButton.addActionListener(e -> { + int choice = JOptionPane.showConfirmDialog( + frame, + "Log off and return to the login screen?" + + "This will end all running Tasks!", + "Confirm Log off", + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE + ); + if (choice != JOptionPane.YES_OPTION) return; + + SwingUtilities.invokeLater(() -> { + try { + Login.main(null); + } catch (Exception ex) { + JOptionPane.showMessageDialog(frame, + "Failed to launch login screen: " + ex.getMessage(), + "Error", + JOptionPane.ERROR_MESSAGE); + return; + } + + kernel.logoff(); + }); + }); + mainPanel.add(shutdownButton, gbc); mainPanel.add(shutdownOS, gbc); + mainPanel.add(logoffButton, gbc); JButton cancelButton = new JButton("Cancel"); cancelButton.setFocusPainted(false); @@ -89,11 +124,11 @@ public class Exit implements DesktopApp { "Are you sure? This will shutdown the Host OS", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE - ); + ); if (choice == JOptionPane.YES_OPTION) { frame.dispose(); - performShutdownCmd(); // cause else the call wouldnt be called + performShutdownCmd(); kernel.shutdown(); } } @@ -107,8 +142,8 @@ public class Exit implements DesktopApp { JOptionPane.WARNING_MESSAGE ); if (choice == JOptionPane.YES_OPTION) { - frame.dispose(); // close the confirmation window first + frame.dispose(); kernel.shutdown(); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/rdesk/applications/system/login/Handler.java b/src/main/java/com/rdesk/applications/system/login/Handler.java new file mode 100644 index 0000000..63003d1 --- /dev/null +++ b/src/main/java/com/rdesk/applications/system/login/Handler.java @@ -0,0 +1,126 @@ + +package com.rdesk.applications.system.login; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.annotations.SerializedName; + +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import java.awt.Window; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; + +public class Handler { + private static final String FILENAME = System.getProperty("user.home") + File.separator + "rsys_passwdstore.json"; + private static final SecureRandom RNG = new SecureRandom(); + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + private static final int SALT_LEN = 16; + private static final int KEY_LEN = 256; // bits + private static final int ITERATIONS = 200_000; + private static final String ALGO = "PBKDF2WithHmacSHA256"; + + + + public static boolean storeExists() { + return new File(FILENAME).exists(); + } + + public static UserRecord load() throws Exception { + File f = new File(FILENAME); + if (!f.exists()) return null; + try (FileReader fr = new FileReader(f)) { + return GSON.fromJson(fr, UserRecord.class); + } + } + + public static void save(UserRecord u) throws Exception { + try (FileWriter fw = new FileWriter(FILENAME)) { + GSON.toJson(u, fw); + } + } + + public static UserRecord createUser(String username, char[] password) throws Exception { + byte[] salt = new byte[SALT_LEN]; + RNG.nextBytes(salt); + byte[] hash = pbkdf2(password, salt, ITERATIONS, KEY_LEN); + UserRecord u = new UserRecord(); + u.username = username; + u.saltB64 = Base64.getEncoder().encodeToString(salt); + u.hashB64 = Base64.getEncoder().encodeToString(hash); + u.iterations = ITERATIONS; + return u; + } + + public static boolean verifyPassword(char[] password, UserRecord stored) throws Exception { + byte[] salt = Base64.getDecoder().decode(stored.saltB64); + byte[] expected = Base64.getDecoder().decode(stored.hashB64); + byte[] computed = pbkdf2(password, salt, stored.iterations, expected.length * 8); + return slowEquals(expected, computed); + } + + public static boolean verifyAndClose(Window window, char[] password, UserRecord stored) throws Exception { + try { + boolean ok = verifyPassword(password, stored); + if (ok && window != null) { + window.dispose(); + } + return ok; + } finally { + clearPassword(password); + } + } + + private static byte[] pbkdf2(char[] password, byte[] salt, int iterations, int keyLengthBits) throws Exception { + PBEKeySpec spec = new PBEKeySpec(password, salt, iterations, keyLengthBits); + SecretKeyFactory skf = SecretKeyFactory.getInstance(ALGO); + return skf.generateSecret(spec).getEncoded(); + } + + private static boolean slowEquals(byte[] a, byte[] b) { + if (a == null || b == null || a.length != b.length) return false; + int diff = 0; + for (int i = 0; i < a.length; i++) diff |= a[i] ^ b[i]; + return diff == 0; + } + + public static void clearPassword(char[] p) { + if (p == null) return; + Arrays.fill(p, (char) 0); + } + + public static String[] listUsers() { + File f = new File(FILENAME); + if (!f.exists()) return new String[0]; + try (FileReader fr = new FileReader(f)) { + JsonElement root = JsonParser.parseReader(fr); + List users = new ArrayList<>(); + if (root.isJsonArray()) { + JsonArray arr = root.getAsJsonArray(); + for (JsonElement el : arr) { + try { + UserRecord ur = GSON.fromJson(el, UserRecord.class); + if (ur != null && ur.username != null) users.add(ur.username); + } catch (Throwable ignore) { /* skip malformed entry */ } + } + } else if (root.isJsonObject()) { + try { + UserRecord ur = GSON.fromJson(root, UserRecord.class); + if (ur != null && ur.username != null) users.add(ur.username); + } catch (Throwable ignore) { /* malformed object -> no users */ } + } + return users.toArray(new String[0]); + } catch (Exception e) { + return new String[0]; + } + } +} diff --git a/src/main/java/com/rdesk/applications/system/login/Login.java b/src/main/java/com/rdesk/applications/system/login/Login.java new file mode 100644 index 0000000..9a5d47c --- /dev/null +++ b/src/main/java/com/rdesk/applications/system/login/Login.java @@ -0,0 +1,267 @@ +package com.rdesk.applications.system.login; + +import com.rdesk.kernel.BootMgr; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.image.BufferedImage; +import java.util.logging.Logger; + +public class Login { + private JFrame frame; + private JComboBox userCombo; + private JTextField userFieldFallback; + private JPasswordField passField; + private JLabel statusLabel; + private UserRecord stored; + private JButton loginBtn; + private JButton closeBtn; + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + try { + new Login().start(); + } catch (Exception e) { + JOptionPane.showMessageDialog(null, e); + System.exit(1); + } + }); + } + + private void start() throws Exception { + log("start(): checking store existence"); + if (!Handler.storeExists()) { + showCreateUserDialog(); + } + stored = Handler.load(); + log("start(): loaded user record: " + (stored != null ? stored.username : "null")); + buildAndShowGui(); + } + + private void buildAndShowGui() { + log("buildAndShowGui(): building GUI"); + frame = new JFrame("rDesk Login"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setResizable(false); + + Image icon = createImageFromSwingIcon(UIManager.getIcon("FileView.computerIcon")); + if (icon != null) frame.setIconImage(icon); + + JPanel panel = new JPanel(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.insets = new Insets(6, 6, 6, 6); + c.anchor = GridBagConstraints.WEST; + c.fill = GridBagConstraints.HORIZONTAL; + + int row = 0; + + if (icon != null) { + JLabel iconLabel = new JLabel(new ImageIcon(icon.getScaledInstance(64, 64, Image.SCALE_SMOOTH))); + GridBagConstraints ic = (GridBagConstraints) c.clone(); + ic.gridx = 0; + ic.gridy = row; + ic.gridheight = 2; + ic.anchor = GridBagConstraints.CENTER; + panel.add(iconLabel, ic); + } + + int colOffset = (icon != null) ? 1 : 0; + + c.gridx = colOffset; + c.gridy = row; + c.gridwidth = 1; + panel.add(new JLabel("Username:"), c); + + c.gridx = colOffset + 1; + c.gridy = row++; + c.weightx = 1.0; + String[] users = fetchUserList(); + if (users.length > 0) { + userCombo = new JComboBox<>(users); + userCombo.setEditable(false); + userCombo.setPreferredSize(new Dimension(160, 24)); + panel.add(userCombo, c); + } else { + userFieldFallback = new JTextField(16); + userFieldFallback.setPreferredSize(new Dimension(160, 24)); + panel.add(userFieldFallback, c); + } + + c.gridx = colOffset; + c.gridy = row; + c.weightx = 0; + panel.add(new JLabel("Password:"), c); + + c.gridx = colOffset + 1; + c.gridy = row++; + c.weightx = 1.0; + passField = new JPasswordField(16); + passField.setPreferredSize(new Dimension(160, 24)); + panel.add(passField, c); + + closeBtn = new JButton("Close"); + closeBtn.addActionListener(e -> frame.dispose()); + loginBtn = new JButton("Login"); + loginBtn.addActionListener(e -> onLogin()); + + c.gridx = colOffset; + c.gridy = row; + c.gridwidth = 1; + c.weightx = 0.5; + c.fill = GridBagConstraints.HORIZONTAL; + panel.add(closeBtn, c); + + c.gridx = colOffset + 1; + c.gridy = row++; + c.weightx = 0.5; + panel.add(loginBtn, c); + + statusLabel = new JLabel(" "); + statusLabel.setForeground(Color.BLUE); + c.gridx = colOffset; + c.gridy = row; + c.gridwidth = 2; + c.weightx = 1.0; + c.fill = GridBagConstraints.HORIZONTAL; + panel.add(statusLabel, c); + + frame.getContentPane().add(panel); + frame.getRootPane().setDefaultButton(loginBtn); + + passField.addActionListener(e -> onLogin()); + if (userFieldFallback != null) userFieldFallback.addActionListener(e -> onLogin()); + if (userCombo != null) { + userCombo.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ENTER"), "login"); + userCombo.getActionMap().put("login", new AbstractAction() { + @Override public void actionPerformed(ActionEvent e) { onLogin(); } + }); + } + + frame.pack(); + Dimension total = frame.getContentPane().getSize(); + int gap = 12; + int buttonWidth = Math.max(90, (total.width - gap) / 2); + closeBtn.setPreferredSize(new Dimension(buttonWidth, 28)); + loginBtn.setPreferredSize(new Dimension(buttonWidth, 28)); + frame.pack(); + + frame.setLocationRelativeTo(null); + frame.setVisible(true); + log("buildAndShowGui(): GUI visible"); + } + + private Image createImageFromSwingIcon(Icon icon) { + if (icon == null) return null; + int w = Math.max(1, icon.getIconWidth()); + int h = Math.max(1, icon.getIconHeight()); + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + Graphics2D g = img.createGraphics(); + try { + icon.paintIcon(null, g, 0, 0); + } finally { + g.dispose(); + } + return img; + } + + private void onLogin() { + String userAttempt = (userCombo != null) + ? String.valueOf(userCombo.getSelectedItem()).trim() + : userFieldFallback.getText().trim(); + char[] passAttempt = passField.getPassword(); + + log("onLogin(): attempt for user='" + userAttempt + "'"); + + if (stored == null) { + statusLabel.setText("No user record found."); + Handler.clearPassword(passAttempt); + return; + } + + if (!stored.username.equals(userAttempt)) { + statusLabel.setText("Invalid username or password."); + Handler.clearPassword(passAttempt); + return; + } + + try { + boolean ok = Handler.verifyAndClose(frame, passAttempt, stored); + if (ok) { + log("onLogin(): authentication successful for user='" + userAttempt + "'"); + statusLabel.setText(" "); + SwingUtilities.invokeLater(() -> { + new SwingWorker() { + @Override protected Void doInBackground() { + try { + BootMgr.launchOrShow(); + log("[Login]: BootManager.launchOrShow() completed"); + } catch (Exception e) { + log("onLogin(): BootManager error: " + e.getMessage()); + } + return null; + } + }.execute(); + }); + } else { + statusLabel.setText("Invalid username or password."); + log("onLogin(): password verification failed for user='" + userAttempt + "'"); + } + } catch (Exception ex) { + ex.printStackTrace(); + statusLabel.setText("Error during verification."); + log("onLogin(): exception during verification: " + ex.getMessage()); + } finally { + Handler.clearPassword(passAttempt); + passField.setText(""); + } + } + + private void showCreateUserDialog() throws Exception { + log("showCreateUserDialog(): creating user dialog"); + JPanel p = new JPanel(new GridLayout(3,2,6,6)); + JTextField user = new JTextField(16); + JPasswordField pass = new JPasswordField(16); + JPasswordField pass2 = new JPasswordField(16); + p.add(new JLabel("Username:")); p.add(user); + p.add(new JLabel("Password:")); p.add(pass); + p.add(new JLabel("Confirm:")); p.add(pass2); + + int res = JOptionPane.showConfirmDialog(null, p, "Create User", JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); + if (res != JOptionPane.OK_OPTION) { + log("showCreateUserDialog(): user cancelled creation, exiting"); + System.exit(0); + } + if (!String.valueOf(pass.getPassword()).equals(String.valueOf(pass2.getPassword()))) { + JOptionPane.showMessageDialog(null, "Passwords do not match.", "Error", JOptionPane.ERROR_MESSAGE); + log("showCreateUserDialog(): passwords did not match"); + showCreateUserDialog(); + return; + } + UserRecord u = Handler.createUser(user.getText().trim(), pass.getPassword()); + Handler.save(u); + log("showCreateUserDialog(): created and saved user '" + u.username + "'"); + JOptionPane.showMessageDialog(null, "User created.", "Success", JOptionPane.INFORMATION_MESSAGE); + } + + private String[] fetchUserList() { + try { + log("fetchUserList(): attempting to retrieve user list from Handler"); + String[] users = Handler.listUsers(); + if (users == null || users.length == 0) { + if (stored != null) { + return new String[]{stored.username}; + } + return new String[0]; + } + return users; + } catch (Exception t) { + if (stored != null) return new String[]{stored.username}; + return new String[0]; + } + } + + private void log(String msg) { + System.out.println("[Login]: " + msg); + } +} diff --git a/src/main/java/com/rdesk/applications/system/login/UserRecord.java b/src/main/java/com/rdesk/applications/system/login/UserRecord.java new file mode 100644 index 0000000..d62c2e8 --- /dev/null +++ b/src/main/java/com/rdesk/applications/system/login/UserRecord.java @@ -0,0 +1,10 @@ +package com.rdesk.applications.system.login; + +import com.google.gson.annotations.SerializedName; + +public class UserRecord { + @SerializedName("username") public String username; + @SerializedName("salt_b64") public String saltB64; + @SerializedName("hash_b64") public String hashB64; + @SerializedName("iterations") public int iterations; +} \ No newline at end of file diff --git a/src/main/java/com/rdesk/kernel/BootMgr.java b/src/main/java/com/rdesk/kernel/BootMgr.java new file mode 100644 index 0000000..1bd9c83 --- /dev/null +++ b/src/main/java/com/rdesk/kernel/BootMgr.java @@ -0,0 +1,40 @@ +package com.rdesk.kernel; + +import javax.swing.*; +import java.awt.*; + +public final class BootMgr { + private static JFrame desktopFrame; + private BootMgr() {} + + public static synchronized void launchOrShow() { + if (desktopFrame == null) { + JFrame f = BootProc.boot(); + if (f != null) desktopFrame = f; + else { + desktopFrame = new JFrame(); + desktopFrame.setContentPane(f); + desktopFrame.pack(); + } + desktopFrame.setVisible(true); + desktopFrame.toFront(); + } else { + if (!desktopFrame.isVisible()) desktopFrame.setVisible(true); + desktopFrame.toFront(); + desktopFrame.requestFocus(); + } + } + + public static synchronized void hideDesktopOnLogout() { + if (desktopFrame != null) { + desktopFrame.setVisible(false); + } + } + + public static synchronized void disposeDesktop() { + if (desktopFrame != null) { + desktopFrame.dispose(); + desktopFrame = null; + } + } +} diff --git a/src/main/java/com/rdesk/kernel/BootProc.java b/src/main/java/com/rdesk/kernel/BootProc.java new file mode 100644 index 0000000..a3740c1 --- /dev/null +++ b/src/main/java/com/rdesk/kernel/BootProc.java @@ -0,0 +1,109 @@ +package com.rdesk.kernel; + +import com.rdesk.applications.entertainment.comic.Xkcd; +import com.rdesk.applications.productivity.Calculator; +import com.rdesk.applications.productivity.Notes; +import com.rdesk.applications.productivity.browsing.TabbedBrowser; +import com.rdesk.applications.productivity.code.CodeDesk; +import com.rdesk.applications.system.Exit; +import com.rdesk.applications.system.TaskManager; +import com.rdesk.applications.system.filehaj.FileExplorerApp; +import com.rdesk.applications.system.rsys.KbChanger; +import com.rdesk.kernel.launcher.AppLauncher; + +import javax.swing.*; + +public class BootProc { + private static final boolean RUN_IN_FS = true; + private static final boolean USE_SYSDEFAULT_LAF = false; + private static final boolean USE_FLATLAF = false; + private static final boolean loadSettingsKernelFlag = true; + + private static JFrame mainFrame; + private static JDesktopPane desktopPane; + + public static synchronized JFrame boot() { + if (mainFrame != null) { + if (!mainFrame.isVisible()) mainFrame.setVisible(true); + mainFrame.toFront(); + mainFrame.requestFocus(); + return mainFrame; + } + + Kernel kernel = Kernel.get(); + kernel.initSettings(loadSettingsKernelFlag); + kernel.boot(); + + mainFrame = new JFrame("rDesk"); + mainFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); + mainFrame.addWindowListener(new java.awt.event.WindowAdapter() { + @Override + public void windowClosing(java.awt.event.WindowEvent e) { + kernel.shutdown(); + } + }); + + if (USE_FLATLAF) { + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.themes.FlatMacLightLaf"); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + JOptionPane.showMessageDialog(null, ex.getMessage() + "@USE_FLATLAF"); + } + } + + if (USE_SYSDEFAULT_LAF) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { + JOptionPane.showMessageDialog(null, ex.getMessage() + "@USE_SYSDEFAULT_LAF"); + } + } + + if (RUN_IN_FS) { + mainFrame.setUndecorated(true); + mainFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); + } else { + mainFrame.setSize(1200, 800); + mainFrame.setLocationRelativeTo(null); + } + + desktopPane = new JDesktopPane(); + kernel.windows().attachDesktop(desktopPane); + kernel.attachFrame(mainFrame); + + AppLauncher launcher = new AppLauncher(kernel); + registerSystemApps(launcher); + + JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, launcher, desktopPane); + split.setDividerSize(0); + split.setEnabled(false); + + mainFrame.setContentPane(split); + mainFrame.setVisible(true); + + return mainFrame; + } + + public static synchronized JFrame getMainFrame() { + return mainFrame; + } + + public static synchronized JDesktopPane getDesktopPane() { + return desktopPane; + } + + private static void registerSystemApps(AppLauncher launcher) { + // productivity + launcher.addApp(new Notes(), "Productivity"); + launcher.addApp(new TabbedBrowser(), "Productivity"); + launcher.addApp(new CodeDesk(), "Productivity"); + launcher.addApp(new Calculator(), "Productivity"); + // entertainment + launcher.addApp(new Xkcd(), "Entertainment"); + // System apps + launcher.addApp(new Exit(), "System"); + launcher.addApp(new TaskManager(), "System"); + launcher.addApp(new FileExplorerApp(), "System"); + launcher.addApp(new KbChanger(), "System"); + } +} diff --git a/src/main/java/com/rdesk/kernel/Kernel.java b/src/main/java/com/rdesk/kernel/Kernel.java index b50d3e2..bf0f228 100644 --- a/src/main/java/com/rdesk/kernel/Kernel.java +++ b/src/main/java/com/rdesk/kernel/Kernel.java @@ -64,6 +64,14 @@ public class Kernel { this.desktopFrame = frame; } + + public void logoff() { + if (running) SwingUtilities.invokeLater(() -> { + desktopFrame.setVisible(false); + }); + } + + public void shutdown() { if (!running) return;