Continuation of: Java OS sorta?
Been a while since I published anything so I figured I would post what I was up to in computer land.
I since migrated my comp from TinyCoreLinux to ArchLinux. I really like the portability of TinyCoreLinux. However, I had trouble using a video driver other than the default vesa driver and I also wanted to learn more about Linux. I uncovered ArchBang Linux and thankfully its maintainer also provides a tutorial on how to create your very own customized version.
Using a combination of the beginner's guide on the ArchLinux website and the ArchBang website I successfully installed ArchLinux on my "trusty" Dell. It took a couple of attempts and modifying the kernel line on the GRUB boot screen but now I'm using the intel driver for the 845g chipset on the laptop (works 99% of the time). The 1% annoyance is that sometimes on bootup the screen will turn off so I have to log in blindly into my desktop/window manager and hit a key binding to shut off/turn on the LCD once more using xrandr which powers up the display. The alternative is physically cycling the laptop again, which I dislike doing.
So how does this relate to the JavaOS? Well it's the same idea I had in TinyCoreLinux in terms of setting up a "Java exclusive" environment. It's not really exclusive in the sense that ArchLinux is the actual operating system running behind the scenes, but after going through various window managers (TWM, OpenBox, JWM, and TinyWM to name a few) I realized I wanted to understand what exactly it was the window manager did/does. The name makes it obvious but it wasn't until I modified my .xinitrc file and typed startx in the console prompt that I really understood what was going on, and then I would say I had an aha Linux moment.
The best part about it was realizing I could run singular applications without all the other stuff to slow it down. So I thought... could I run a Java program that would take up the whole screen? Not really a JavaOS, but more of a Java window manager that has the ability to run other Java applications?
I looked at a ScreenManager class supplied by David Brackeen of brackeen.com as supplied in the source code of a Java game programming book he authored. Modified it a bit to catch/handle some exceptions he seemed to ignore and allow the ability to supply your own custom Swing JFrame rather than use the JFrame as a giant canvas. Finally, I modified another bit of his source code to actually make use of the ScreenManager class and instantiate a virtual desktop. The only real elegance it provides is that what would be considered the launchbar/start menu/taskbar/whatever other name it takes on is a JMenuBar which fits nicely into a JFrame by default, the content pane of the JFrame is a JTabbedPane which allows me to create multiple tabs (I allowed a maximum of 10 so as to be able to use a mnemonic to switch between each using the number keys and Alt combination). Each of the tabs created then gets populated with a JDesktopPane, which would allow you to create "applications" using JInternalFrames. This encapsulates the handling of windows/desktops in Java.
Here's the code:
ScreenManager.java
VirtualDesktop.java
And of course the mandatory screenshots (I have it running Nimbus theme by default, sue me for liking pretty):
How it looks on launch

The menu options to add/remove desktops and exit

The maximum number of desktops

My .xinitrc file has a the following line:
This gives the JVM a higher priority and the only other processes (for my unique user) running are startx, xinit, dbus-launch and dbus-daemon. I would make a wild guess that the JVM doesn't really interact with dbus so I might be able to get away with disabling it. All other processes are root ArchLinux processes, such as network setup and the like.
I'm not skilled enough to really make a JavaWM this is more of a "hey neato, wonder where this could go?" idea. This is not something that is within the realm of possibility for me given what I know about programming and what I know about OS concepts (which boils down to nothing, in terms of programming). It would be great though if it might inspire a Java guru on here to actualize the concept, so here's to dreaming...
Been a while since I published anything so I figured I would post what I was up to in computer land.
I since migrated my comp from TinyCoreLinux to ArchLinux. I really like the portability of TinyCoreLinux. However, I had trouble using a video driver other than the default vesa driver and I also wanted to learn more about Linux. I uncovered ArchBang Linux and thankfully its maintainer also provides a tutorial on how to create your very own customized version.
Using a combination of the beginner's guide on the ArchLinux website and the ArchBang website I successfully installed ArchLinux on my "trusty" Dell. It took a couple of attempts and modifying the kernel line on the GRUB boot screen but now I'm using the intel driver for the 845g chipset on the laptop (works 99% of the time). The 1% annoyance is that sometimes on bootup the screen will turn off so I have to log in blindly into my desktop/window manager and hit a key binding to shut off/turn on the LCD once more using xrandr which powers up the display. The alternative is physically cycling the laptop again, which I dislike doing.
So how does this relate to the JavaOS? Well it's the same idea I had in TinyCoreLinux in terms of setting up a "Java exclusive" environment. It's not really exclusive in the sense that ArchLinux is the actual operating system running behind the scenes, but after going through various window managers (TWM, OpenBox, JWM, and TinyWM to name a few) I realized I wanted to understand what exactly it was the window manager did/does. The name makes it obvious but it wasn't until I modified my .xinitrc file and typed startx in the console prompt that I really understood what was going on, and then I would say I had an aha Linux moment.
The best part about it was realizing I could run singular applications without all the other stuff to slow it down. So I thought... could I run a Java program that would take up the whole screen? Not really a JavaOS, but more of a Java window manager that has the ability to run other Java applications?
I looked at a ScreenManager class supplied by David Brackeen of brackeen.com as supplied in the source code of a Java game programming book he authored. Modified it a bit to catch/handle some exceptions he seemed to ignore and allow the ability to supply your own custom Swing JFrame rather than use the JFrame as a giant canvas. Finally, I modified another bit of his source code to actually make use of the ScreenManager class and instantiate a virtual desktop. The only real elegance it provides is that what would be considered the launchbar/start menu/taskbar/whatever other name it takes on is a JMenuBar which fits nicely into a JFrame by default, the content pane of the JFrame is a JTabbedPane which allows me to create multiple tabs (I allowed a maximum of 10 so as to be able to use a mnemonic to switch between each using the number keys and Alt combination). Each of the tabs created then gets populated with a JDesktopPane, which would allow you to create "applications" using JInternalFrames. This encapsulates the handling of windows/desktops in Java.
Here's the code:
ScreenManager.java
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
/**
The ScreenManager class manages initializing and displaying
full screen graphics modes.
*/
public class ScreenManager
{
private GraphicsDevice device;
/**
Creates a new ScreenManager object.
*/
public ScreenManager()
{
GraphicsEnvironment environment =
GraphicsEnvironment.getLocalGraphicsEnvironment();
try
{
device = environment.getDefaultScreenDevice();
}
catch(HeadlessException ex)
{
System.err.println("Current environment does not support display/keyboard/mouse.");
ex.printStackTrace();
System.exit(-1);
}
}
/**
Returns a list of compatible display modes for the
default device on the system.
*/
public DisplayMode[] getCompatibleDisplayModes()
{
return device.getDisplayModes();
}
/**
Returns the first compatible mode in a list of modes.
Returns null if no modes are compatible.
*/
public DisplayMode findFirstCompatibleMode(
DisplayMode modes[])
{
DisplayMode goodModes[] = device.getDisplayModes();
for(int i = 0; i < modes.length; i++)
{
for(int j = 0; j < goodModes.length; j++)
{
if(displayModesMatch(modes[i], goodModes[j]))
{
return modes[i];
}
}
}
return null;
}
/**
Returns the current display mode.
*/
public DisplayMode getCurrentDisplayMode()
{
return device.getDisplayMode();
}
/**
Determines if two display modes "match". Two display
modes match if they have the same resolution, bit depth,
and refresh rate. The bit depth is ignored if one of the
modes has a bit depth of DisplayMode.BIT_DEPTH_MULTI.
Likewise, the refresh rate is ignored if one of the
modes has a refresh rate of
DisplayMode.REFRESH_RATE_UNKNOWN.
*/
public boolean displayModesMatch(DisplayMode modeA,
DisplayMode modeB)
{
if(modeA.getWidth() != modeB.getWidth() ||
modeA.getHeight() != modeB.getHeight())
{
return false;
}
if(modeA.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI &&
modeB.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI &&
modeA.getBitDepth() != modeB.getBitDepth())
{
return false;
}
if(modeA.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN &&
modeB.getRefreshRate() != DisplayMode.REFRESH_RATE_UNKNOWN &&
modeA.getRefreshRate() != modeB.getRefreshRate())
{
return false;
}
return true;
}
/**
Enters full screen mode and changes the display mode.
If the specified display mode is null or not compatible
with this device, or if the display mode cannot be
changed on this system, the current display mode is used.
The display uses a BufferStrategy with 2 buffers.
*/
public void setFullScreen(JFrame frame, DisplayMode displayMode)
{
frame.setUndecorated(true); // IllegalComponentStateException cannot (SHOULD NOT) occur upon creation JFrame automatically meets requirements
frame.setIgnoreRepaint(true);
frame.setResizable(false);
if(device.isFullScreenSupported())
{
device.setFullScreenWindow(frame);
if(displayMode != null &&
device.isDisplayChangeSupported())
{
try
{
device.setDisplayMode(displayMode);
}
catch(IllegalArgumentException ex)
{
// DisplayMode dm was null or is not a valid mode according to environment
}
}
try{
frame.createBufferStrategy(2); // IllegalArgumentException cannot (SHOULD NOT) occur as int numBuffers > 0
}
catch(IllegalStateException ex)
{
System.err.println("Frame could not be double buffered.");
ex.printStackTrace();
System.exit(-1);
}
}
}
/**
Gets the graphics context for the display. The
ScreenManager uses double buffering, so applications must
call update() to show any graphics drawn.
The application must dispose of the graphics object.
*/
public Graphics2D getGraphics(){
Window window = device.getFullScreenWindow();
if(window != null) // null window would imply there isn't a full screen window available
{
BufferStrategy strategy = window.getBufferStrategy();
return (Graphics2D)strategy.getDrawGraphics();
}
else
{
return null;
}
}
/**
Updates the display.
*/
public void update()
{
Window window = device.getFullScreenWindow();
if(window != null)
{
BufferStrategy strategy = window.getBufferStrategy();
if(!strategy.contentsLost()){
strategy.show();
}
}
// Sync the display on some systems.
// (on Linux, this fixes event queue problems)
try
{
Toolkit.getDefaultToolkit().sync();
}catch(AWTError ex)
{
System.err.println("A toolkit could not be found/accessed/instantiated");
ex.printStackTrace();
System.exit(-1);
}
}
/**
Returns the window currently used in full screen mode.
Returns null if the device is not in full screen mode.
*/
public Window getFullScreenWindow(){
return device.getFullScreenWindow();
}
/**
Returns the width of the window currently used in full
screen mode. Returns 0 if the device is not in full
screen mode.
*/
public int getWidth(){
Window window = device.getFullScreenWindow();
if(window != null)
{
return window.getWidth();
}
else
{
return 0;
}
}
/**
Returns the height of the window currently used in full
screen mode. Returns 0 if the device is not in full
screen mode.
*/
public int getHeight(){
Window window = device.getFullScreenWindow();
if(window != null)
{
return window.getHeight();
}
else
{
return 0;
}
}
/**
Restores the screen's display mode.
*/
public void restoreScreen(){
Window window = device.getFullScreenWindow();
if(window != null){
window.dispose();
}
device.setFullScreenWindow(null);
}
/**
Creates an image compatible with the current display.
*/
public BufferedImage createCompatibleImage(int w, int h,
int transparency)
{
Window window = device.getFullScreenWindow();
if(window != null)
{
GraphicsConfiguration gc =
window.getGraphicsConfiguration();
return gc.createCompatibleImage(w, h, transparency);
}
return null;
}
}
VirtualDesktop.java
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JSeparator;
import javax.swing.JDesktopPane;
import javax.swing.KeyStroke;
import javax.swing.JTabbedPane;
// import javax.swing.JLabel;
public class VirtualDesktop {
public static void main(String args[]) {
VirtualDesktop virtualDesktop = new VirtualDesktop();
virtualDesktop.run();
}
private static final DisplayMode POSSIBLE_MODES[] = {
new DisplayMode(800, 600, 32, 0),
new DisplayMode(800, 600, 24, 0),
new DisplayMode(800, 600, 16, 0),
new DisplayMode(640, 480, 32, 0),
new DisplayMode(640, 480, 24, 0),
new DisplayMode(640, 480, 16, 0)
};
private static final byte MAX_DESKTOPS = 10;
private JTabbedPane tabbedDesktops;
private ScreenManager screen;
public void run() {
screen = new ScreenManager();
DisplayMode displayMode =
screen.findFirstCompatibleMode(POSSIBLE_MODES);
screen.setFullScreen(createDesktop(), displayMode);
render();
}
public void render()
{
Graphics2D g = screen.getGraphics();
draw(g);
g.dispose();
screen.update();
}
public void draw(Graphics2D g) {
screen.getFullScreenWindow().paintComponents(g);
}
public JFrame createDesktop(){
JFrame frame = new JFrame();
// Create initial desktop
tabbedDesktops = new JTabbedPane(JTabbedPane.BOTTOM);
tabbedDesktops.addTab("Desktop " + tabbedDesktops.getTabCount(), new JDesktopPane());
tabbedDesktops.setMnemonicAt(0,
KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_0));
frame.setContentPane(tabbedDesktops);
// Create system menu
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("JavaWM");
menu.setMnemonic(
KeyEvent.getExtendedKeyCodeForChar(KeyEvent.VK_J));
// Desktops sub menu
JMenu subMenu = new JMenu("Desktops");
JMenuItem menuItem = new JMenuItem("Add");
ActionListener menuListener = new ActionListener() {
public void actionPerformed(ActionEvent e){
if(tabbedDesktops.getTabCount() < MAX_DESKTOPS)
{
byte tabCount = (byte)tabbedDesktops.getTabCount();
tabbedDesktops.addTab("Desktop " + tabCount, new JDesktopPane());
tabbedDesktops.setMnemonicAt(tabCount, KeyEvent.VK_0 + tabCount);
}
}
};
menuItem.addActionListener(menuListener);
subMenu.add(menuItem);
menuItem = new JMenuItem("Remove");
menuListener = new ActionListener() {
public void actionPerformed(ActionEvent e){
if(tabbedDesktops.getTabCount() > 1)
{
tabbedDesktops.removeTabAt(tabbedDesktops.getTabCount() - 1);
}
}
};
menuItem.addActionListener(menuListener);
subMenu.add(menuItem);
subMenu.add(new JSeparator());
menu.add(subMenu);
menu.add(new JSeparator());
// Exit JavaWM
menuItem = new JMenuItem("Exit");
menuItem.setAccelerator(KeyStroke.getKeyStroke(
KeyEvent.VK_END,
InputEvent.CTRL_DOWN_MASK | InputEvent.ALT_DOWN_MASK));
menuListener = new ActionListener() {
public void actionPerformed(ActionEvent e){
screen.restoreScreen();
}
};
menuItem.addActionListener(menuListener);
menu.add(menuItem);
menuBar.add(menu);
frame.setJMenuBar(menuBar);
return frame;
}
}
And of course the mandatory screenshots (I have it running Nimbus theme by default, sue me for liking pretty):
How it looks on launch

The menu options to add/remove desktops and exit

The maximum number of desktops

My .xinitrc file has a the following line:
exec nice -n -10 java ...Where ... represents the -cp classpath and classname (VirtualDesktop).
This gives the JVM a higher priority and the only other processes (for my unique user) running are startx, xinit, dbus-launch and dbus-daemon. I would make a wild guess that the JVM doesn't really interact with dbus so I might be able to get away with disabling it. All other processes are root ArchLinux processes, such as network setup and the like.
I'm not skilled enough to really make a JavaWM this is more of a "hey neato, wonder where this could go?" idea. This is not something that is within the realm of possibility for me given what I know about programming and what I know about OS concepts (which boils down to nothing, in terms of programming). It would be great though if it might inspire a Java guru on here to actualize the concept, so here's to dreaming...
9 Comments On This Entry
Page 1 of 1
cfoley
19 December 2011 - 06:49 AM
Pretty cool idea. Do you have Java apps for all the tasks you normally do? How about a terminal?
Sounds like whoever wrote that tutorial was overcomplicating things. All you need to is make a panel with a label and a button, and add an action listener to the button to close the tab. Here is a quick example I threw together:
I'm sure you can make it pretty yourself.
Here is an example app which shows how to set a ClosableTab as the tab for the JTabbedPane:
Sounds like whoever wrote that tutorial was overcomplicating things. All you need to is make a panel with a label and a button, and add an action listener to the button to close the tab. Here is a quick example I threw together:
class ClosableTab extends JPanel implements ActionListener {
private JTabbedPane owner;
ClosableTab(String title, JTabbedPane owner) {
super(new BorderLayout());
this.owner = owner;
JButton closeButton = new JButton("X");
closeButton.addActionListener(this);
add(new JLabel(title), BorderLayout.CENTER);
add(closeButton, BorderLayout.EAST);
}
@Override
public void actionPerformed(ActionEvent e) {
int index = owner.indexOfTabComponent(this);
owner.remove(index);
}
}
I'm sure you can make it pretty yourself.
public class CloseTabDemo {
private JTabbedPane tabs = new JTabbedPane();
private char nextLetter = 'A';
CloseTabDemo() {
JButton newTab = new JButton("[+] New Tab");
newTab.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addTab("Tab " + nextLetter++);
}
});
JFrame window = new JFrame("Tab close button demo");
window.add(newTab, BorderLayout.NORTH);
window.add(tabs, BorderLayout.CENTER);
window.setSize(800, 600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public static void main(String[] args) {
new CloseTabDemo();
}
void addTab(String title) {
tabs.addTab(title, new JTextArea());
int index = tabs.getTabCount() - 1;
tabs.setTabComponentAt(index, new ClosableTab(title, tabs));
}
}
Vampiricx3
19 December 2011 - 05:02 PM
I would so use this.
looks cool, kind of like an ubuntu cross with Windows OS.
cfoley
20 December 2011 - 06:48 AM
I've not seen the tutorial you are referring to, but it's certainly possible to have a roll-over button without digging too far into the API. I've modified my previous example to demonstrate. Please excuse the ugliness in the messy code and tabs resizing. I only had 10 mins to hack something together. You should be able to see what's going on though.
public class CloseTabDemo implements MouseMotionListener {
private JTabbedPane tabs = new JTabbedPane();
private char nextLetter = 'A';
private int hoverIndex = -1;
CloseTabDemo() {
JButton newTab = new JButton("[+] New Tab");
newTab.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addTab("Tab " + nextLetter++);
}
});
tabs.addMouseMotionListener(this);
JFrame window = new JFrame("Tab close button demo");
window.add(newTab, BorderLayout.NORTH);
window.add(tabs, BorderLayout.CENTER);
window.setSize(800, 600);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setVisible(true);
}
public static void main(String[] args) {
new CloseTabDemo();
}
void addTab(String title) {
tabs.addTab(title, new JTextArea());
int index = tabs.getTabCount() - 1;
tabs.setTabComponentAt(index, new ClosableTab(title, tabs));
}
@Override public void mouseDragged(MouseEvent e) {mouseMoved(e);}
@Override
public void mouseMoved(MouseEvent e) {
int newIndex = tabs.indexAtLocation(e.getX(), e.getY());
if (newIndex != hoverIndex) {
if (hoverIndex != -1) {
ClosableTab tab = (ClosableTab)tabs.getTabComponentAt(hoverIndex);
tab.hideButton();
}
if (newIndex != -1) {
ClosableTab tab = (ClosableTab)tabs.getTabComponentAt(newIndex);
tab.showButton();
}
hoverIndex = newIndex;
}
}
}
class ClosableTab extends JPanel implements ActionListener {
private JTabbedPane owner;
private JButton closeButton = new JButton("X");
ClosableTab(String title, JTabbedPane owner) {
super(new BorderLayout());
this.owner = owner;
closeButton.addActionListener(this);
hideButton();
add(new JLabel(title), BorderLayout.CENTER);
add(closeButton, BorderLayout.EAST);
}
@Override
public void actionPerformed(ActionEvent e) {
int index = owner.indexOfTabComponent(this);
owner.remove(index);
}
void showButton(){closeButton.setVisible(true);};
void hideButton(){closeButton.setVisible(false);};
}
RCR
06 July 2012 - 11:38 AM
Do you mind if I continue on this? As like a joint project. I would give you credit. Just curious.
Thanks
- RCR
Thanks
- RCR
Page 1 of 1
|
|



9 Comments








|