So I've been using Arch Linux as my distro of choice. I'll tell you why with a screenshot:

The setup has been involved, so it definitely wasn't fun (at first). However, I have learned quite a bit. For instance, before, I was using an ethernet bridge since I hadn't been able to determine how to set up the PCMCIA card. I guess once one thing makes sense, more things start to make sense and I was able to set up and get the PCMCIA card working (that was also a headache). However, I digress.
One of the, let's call it "novice" techniques I was using was trying to find specific software that would do what I wanted on my machine. For instance, I had used a neat application called nitrogen for managing my wallpapers, and secondly an application called scrot for taking screenshots. They're good, lightweight apps for doing so, readily available from the repository.
For image manipulation I would use imagemagick's convert command line utility. Recently, I figured out it will also take screenshots and you can set your wallpaper with it. Linux just keeps getting better and better. This meant I wouldn't need nitrogen or scrot anymore. The only issue is that imagemagick's command line can get fairly cryptic, which I didn't much like. Furthermore, to be very much a non-geek, I just happen to prefer GUIs for things like this as opposed to command line.
I didn't want to bother with having to try and remind myself or decipher what the proper command would be each time I wanted to change my wallpaper (as I don't do it frequently). So I decided I would code a Java application to do this tedious work for me. I hate when I get an idea like this because it always turns out to be more work than I naively thought beforehand.
So here's what I wanted the application to do for me: allow me to pick a wallpaper, select how I want the wallpaper applied (stretched, cropped or padded), then execute the relevant imagemagick command. Here is what I've coded so far:
Wallmagick.java
FrameDragManager.java
StyleSetter.java
WallPaperSetter.java
Right now it's operational and sets the wallpaper as intended. However, I still have to implement a graphical JFileChooser and handle exceptions and such more elegantly. Another oddity is my use of a JWindow and JInternalFrame. Basically, I did this because I wanted to be able to instantiate the application in an X server without a window manager. I also wanted to ensure the look and feel (Nimbus). The config.xml file uses the try-with so I included a jvm version check (as it's only supposed to work in 1.7 and Nimbus wasn't on all 1.6 versions). The application should also generate a modal dialog that gives you the command line for imagemagick so you can prepend it to your ~/.xprofile or ~/.xinitrc and have the wallpaper autoset on startup. I created the config.xml along those same lines, but it's silly to call a java -jar Wallmagick.jar -restore or something to that effect with the overhead of the jvm rather than just using imagemagick directly.
Anyhow, suggestions for improvements or different/better way of doing things are also welcome.
EDIT: Forgot to post what it looks like.

The setup has been involved, so it definitely wasn't fun (at first). However, I have learned quite a bit. For instance, before, I was using an ethernet bridge since I hadn't been able to determine how to set up the PCMCIA card. I guess once one thing makes sense, more things start to make sense and I was able to set up and get the PCMCIA card working (that was also a headache). However, I digress.
One of the, let's call it "novice" techniques I was using was trying to find specific software that would do what I wanted on my machine. For instance, I had used a neat application called nitrogen for managing my wallpapers, and secondly an application called scrot for taking screenshots. They're good, lightweight apps for doing so, readily available from the repository.
For image manipulation I would use imagemagick's convert command line utility. Recently, I figured out it will also take screenshots and you can set your wallpaper with it. Linux just keeps getting better and better. This meant I wouldn't need nitrogen or scrot anymore. The only issue is that imagemagick's command line can get fairly cryptic, which I didn't much like. Furthermore, to be very much a non-geek, I just happen to prefer GUIs for things like this as opposed to command line.
I didn't want to bother with having to try and remind myself or decipher what the proper command would be each time I wanted to change my wallpaper (as I don't do it frequently). So I decided I would code a Java application to do this tedious work for me. I hate when I get an idea like this because it always turns out to be more work than I naively thought beforehand.
So here's what I wanted the application to do for me: allow me to pick a wallpaper, select how I want the wallpaper applied (stretched, cropped or padded), then execute the relevant imagemagick command. Here is what I've coded so far:
Wallmagick.java
/* * Icons taken from http://p.yusukekamiyamane.com/ * http://www.iconarchive.com/show/fugue-icons-by-yusuke-kamiyamane/document-image-icon.html */ import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JWindow; import javax.swing.JInternalFrame; import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; import javax.swing.JRadioButton; import javax.swing.BorderFactory; import javax.swing.border.TitledBorder; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; import java.awt.BorderLayout; import java.awt.Component; import java.awt.GridLayout; import java.awt.GraphicsEnvironment; import java.awt.GraphicsDevice; import java.awt.DisplayMode; import java.awt.Window; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Properties; public class Wallmagick { public static final double REQUIRED_JVM_VERSION = 1.7; public static final String CONFIGURATION_FILENAME = "config.xml"; // Wallpaper display styles public static final String STRETCH = "Stretch"; public static final String PAD = "Pad"; public static final String CROP = "Crop"; private static void createAndShowGUI(Properties configuration) { // Create left panel with 5 radio buttons for display style of wallpaper JRadioButton stretchButton = new JRadioButton(STRETCH); JRadioButton padButton = new JRadioButton(PAD); JRadioButton cropButton = new JRadioButton(CROP); StyleSetter styleListener = new StyleSetter(configuration); stretchButton.addActionListener(styleListener); padButton.addActionListener(styleListener); cropButton.addActionListener(styleListener); switch (configuration.getProperty("style")) { case STRETCH: stretchButton.setSelected(true); break; case PAD: padButton.setSelected(true); break; case CROP: cropButton.setSelected(true); break; } ButtonGroup displayRadioButtons = new ButtonGroup(); displayRadioButtons.add(stretchButton); displayRadioButtons.add(padButton); displayRadioButtons.add(cropButton); TitledBorder titledBorder = BorderFactory.createTitledBorder("Display"); JPanel leftPanel = new JPanel(new GridLayout(0, 1)); leftPanel.add(stretchButton); leftPanel.add(padButton); leftPanel.add(cropButton); leftPanel.setBorder(titledBorder); // Create right panel button with two standard buttons JButton wallpaperButton = new JButton("Wallpaper"); wallpaperButton.setAlignmentX(Component.CENTER_ALIGNMENT); JButton applyButton = new JButton("Apply"); applyButton.setAlignmentX(Component.CENTER_ALIGNMENT); // Set wallpaper using imagemagick's display command applyButton.addActionListener(new WallpaperSetter(configuration)); JPanel rightPanel = new JPanel(); rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS)); rightPanel.add(Box.createVerticalGlue()); rightPanel.add(wallpaperButton); rightPanel.add(applyButton); rightPanel.add(Box.createVerticalGlue()); // Load application icon String iconFile = configuration.getProperty("config.path"); iconFile += configuration.getProperty("file.separator"); iconFile += "document-image-icon.png"; ImageIcon icon = new ImageIcon(iconFile); JInternalFrame frame = new JInternalFrame("Wallmagick", false, true, false, false); frame.setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE); frame.getContentPane().add(leftPanel, BorderLayout.WEST); frame.getContentPane().add(rightPanel, BorderLayout.CENTER); frame.setFrameIcon(icon); frame.pack(); frame.setVisible(true); frame.addInternalFrameListener(new InternalFrameAdapter() { public void internalFrameClosed(InternalFrameEvent e) { for(Window windows : window.getWindows()){ if(windows.getName().equals(e.getInternalFrame().getTopLevelAncestor().getName())){ windows.dispose(); break; } } System.exit(0); } }); FrameDragManager frameDragManager = new FrameDragManager(); frame.addComponentListener(frameDragManager); JWindow window = new JWindow(); window.getContentPane().add(frame); window.pack(); window.setLocationRelativeTo(null); window.setVisible(true); } public static Properties getConfiguration() { // Confirm Java Virtual Machine version try { double jvmversion = Double.parseDouble(System .getProperty("java.vm.specification.version")); if (jvmversion < REQUIRED_JVM_VERSION) { throw new Exception(); } } catch (Exception e) { System.err.println("JVM version check failed."); System.exit(1); } // Determine config.xml path Path configPath = null; String fileSeparator = new String(); try { String configFile = System.getProperty("java.class.path"); fileSeparator = System.getProperty("file.separator"); if (!configFile.endsWith(fileSeparator)) { configFile += fileSeparator; } configFile += CONFIGURATION_FILENAME; configPath = Paths.get(configFile).toAbsolutePath(); } catch (Exception e) { System.err.println("Unable to determine configuration path."); System.exit(1); } // Test if configuration is readable/exists boolean configReadable = false; try { configReadable = Files.isReadable(configPath); } catch (Exception e) { configReadable = false; } // Instantiate Wallmagick properties Properties configuration = new Properties(); configuration.setProperty("wallpaper.path", /*configPath.getParent() .toString()*/ "/home/tron/.wallpapers"); configuration.setProperty("wallpaper.image", "tron.png"); configuration.setProperty("style", STRETCH); // Load properties from configuration file if possible if (configReadable) { try (InputStream configStream = Files.newInputStream(configPath)) { configuration.loadFromXML(configStream); } catch (Exception e) { System.err.println("Unable to read configuration file."); System.exit(1); } } // These configuration properties are dynamic configuration.setProperty("file.separator", fileSeparator); configuration.setProperty("config.path", configPath.getParent() .toString()); // Determine display's current resolution int height = 0; int width = 0; try { GraphicsDevice graphicsDevice = GraphicsEnvironment .getLocalGraphicsEnvironment().getDefaultScreenDevice(); DisplayMode displayMode = graphicsDevice.getDisplayMode(); height = displayMode.getHeight(); width = displayMode.getWidth(); } catch (Exception e) { System.err.println("System is running headless."); System.exit(1); } configuration.setProperty("display.width", String.valueOf(width)); configuration.setProperty("display.height", String.valueOf(height)); return configuration; } public static void main(String[] args) { // Event Dispatch Thread javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { // Set Nimbus L&F try { for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (Exception e) { System.err.println("Nimbus L&F not supported."); System.exit(1); } // Display GUI createAndShowGUI(getConfiguration()); } }); } }
FrameDragManager.java
import java.awt.event.ComponentEvent; import java.awt.Component; import java.awt.event.ComponentAdapter; import javax.swing.JInternalFrame; import javax.swing.JWindow; import java.awt.MouseInfo; import java.awt.Point; public class FrameDragManager extends ComponentAdapter { public void componentMoved(ComponentEvent e) { try{ JInternalFrame frame = (JInternalFrame)e.getComponent(); JWindow window = (JWindow)frame.getTopLevelAncestor(); Point mousePoint = MouseInfo.getPointerInfo().getLocation(); Point windowPoint = new Point(); windowPoint.setLocation( mousePoint.getX() - window.getWidth() / 2.0, mousePoint.getY() ); for(Component components : frame.getComponents()){ if(!"JRootPane".equals(components.getClass().getSimpleName())){ windowPoint.setLocation( mousePoint.getX() - window.getWidth() / 2.0, mousePoint.getY() - components.getHeight() / 2.0 ); break; } } window.setLocation(windowPoint); }catch(Exception ex){ System.err.println("Unable to drag window."); } } }
StyleSetter.java
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; import javax.swing.JRadioButton; public class StyleSetter implements ActionListener { private Properties configuration; public StyleSetter(Properties configuration){ this.configuration = configuration; } public void actionPerformed(ActionEvent e){ JRadioButton selectedButton = (JRadioButton)e.getSource(); configuration.setProperty("style", selectedButton.getText()); } }
WallPaperSetter.java
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Properties; public class WallpaperSetter implements ActionListener { private Properties configuration; public WallpaperSetter(Properties configuration){ this.configuration = configuration; } public void actionPerformed(ActionEvent e){ String wallpaper = configuration.getProperty("wallpaper.path"); wallpaper += configuration.getProperty("file.separator"); wallpaper += configuration.getProperty("wallpaper.image"); int displayWidth = Integer.parseInt(configuration.getProperty("display.width")); int displayHeight = Integer.parseInt(configuration.getProperty("display.height")); String pipedCommand = ""; switch(configuration.getProperty("style")){ case Wallmagick.STRETCH: pipedCommand = "convert -resize "; pipedCommand += displayWidth; pipedCommand += "x"; pipedCommand += displayHeight; pipedCommand += "\\! "; pipedCommand += wallpaper; pipedCommand += " - | display -window root -"; break; case Wallmagick.PAD: pipedCommand = "convert -resize "; pipedCommand += displayWidth; pipedCommand += "x"; pipedCommand += displayHeight; pipedCommand += "\\> -background black -gravity center -extent "; pipedCommand += displayWidth; pipedCommand += "x"; pipedCommand += displayHeight; pipedCommand += " "; pipedCommand += wallpaper; pipedCommand += " - | display -window root -"; break; case Wallmagick.CROP: pipedCommand = "convert -resize "; pipedCommand += displayWidth; pipedCommand += "x"; pipedCommand += displayHeight; pipedCommand += "^ -gravity center -extent "; pipedCommand += displayWidth; pipedCommand += "x"; pipedCommand += displayHeight; pipedCommand += " "; pipedCommand += wallpaper; pipedCommand += " - | display -window root -"; break; } String[] command = { "/bin/sh", "-c", pipedCommand }; try { Runtime.getRuntime().exec(command); } catch(Exception ex) { System.err.println("Unable to execute imagemagick."); System.exit(1); } } }
Right now it's operational and sets the wallpaper as intended. However, I still have to implement a graphical JFileChooser and handle exceptions and such more elegantly. Another oddity is my use of a JWindow and JInternalFrame. Basically, I did this because I wanted to be able to instantiate the application in an X server without a window manager. I also wanted to ensure the look and feel (Nimbus). The config.xml file uses the try-with so I included a jvm version check (as it's only supposed to work in 1.7 and Nimbus wasn't on all 1.6 versions). The application should also generate a modal dialog that gives you the command line for imagemagick so you can prepend it to your ~/.xprofile or ~/.xinitrc and have the wallpaper autoset on startup. I created the config.xml along those same lines, but it's silly to call a java -jar Wallmagick.jar -restore or something to that effect with the overhead of the jvm rather than just using imagemagick directly.
Anyhow, suggestions for improvements or different/better way of doing things are also welcome.
EDIT: Forgot to post what it looks like.

6 Comments On This Entry
Page 1 of 1

bigmatt267
03 March 2014 - 06:18 PM
That's pretty bad azz, but why didn't you use
import javax.swing.*?
Page 1 of 1