public DrawingPanel(int width, int height) {
        if (width < 0 || width > MAX_SIZE || height < 0 || height > MAX_SIZE) {
            throw new IllegalArgumentException("Illegal width/height: " + width + " x " + height);
        }
        
        checkAnimationSettings();
        
        synchronized (getClass()) {
            instances++;
            instanceNumber = instances;  // each DrawingPanel stores its own int number
            
            if (shutdownThread == null && !usingDrJava()) {
                shutdownThread = new Thread(new Runnable() {
                    // Runnable implementation; used for shutdown thread.
                    public void run() {
                        try {
                            while (true) {
                                // maybe shut down the program, if no more DrawingPanels are onscreen
                                // and main has finished executing
                                if ((instances == 0 || shouldSave()) && !mainIsActive()) {
                                    try {
                                        System.exit(0);
                                    } catch (SecurityException sex) {}
                                }

                                Thread.sleep(250);
                            }
                        } catch (Exception e) {}
                    }
                });
                shutdownThread.setPriority(Thread.MIN_PRIORITY);
                shutdownThread.start();
            }
        }
        this.width = width;
        this.height = height;
        
        if (DEBUG) System.out.println("w=" + width + ",h=" + height + ",anim=" + isAnimated() + ",graph=" + isGraphical() + ",save=" + shouldSave());
        
        if (isAnimated() && shouldSave()) {
            // image must be no more than 256 colors
            image = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED);
            // image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            PRETTY = false;   // turn off anti-aliasing to save palette colors
            
            // initially fill the entire frame with the background color,
            // because it won't show through via transparency like with a full ARGB image
            Graphics g = image.getGraphics();
            g.setColor(backgroundColor);
            g.fillRect(0, 0, width + 1, height + 1);
        } else {
            image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        }
        initialPixel = image.getRGB(0, 0);
        
        g2 = (Graphics2D) image.getGraphics();
        g2.setColor(Color.BLACK);
        if (PRETTY) {
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        }
        
        if (isAnimated()) {
            initializeAnimation();
        }
        
        if (isGraphical()) {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {}
            
            statusBar = new JLabel(" ");
            statusBar.setBorder(BorderFactory.createLineBorder(Color.BLACK));
            
            panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
            panel.setBackground(backgroundColor);
            panel.setPreferredSize(new Dimension(width, height));
            imagePanel = new ImagePanel(image);
            imagePanel.setBackground(backgroundColor);
            panel.add(imagePanel);
            
            // listen to mouse movement
            panel.addMouseMotionListener(this);
            
            // main window frame
            frame = new JFrame(TITLE);
            // frame.setResizable(false);
            frame.addWindowListener(this);
            // JPanel center = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
            JScrollPane center = new JScrollPane(panel);
            // center.add(panel);
            frame.getContentPane().add(center);
            frame.getContentPane().add(statusBar, "South");
            frame.setBackground(Color.DARK_GRAY);

            // menu bar
            setupMenuBar();
            
            frame.pack();
            center(frame);
            frame.setVisible(true);
            if (!shouldSave()) {
                toFront(frame);
            }
            
            // repaint timer so that the screen will update
            createTime = System.currentTimeMillis();
            timer = new Timer(DELAY, this);
            timer.start();
        } else if (shouldSave()) {
            // headless mode; just set a hook on shutdown to save the image
            callingClassName = getCallingClassName();
            try {
                Runtime.getRuntime().addShutdownHook(new Thread(this));
            } catch (Exception e) {
                if (DEBUG) System.out.println("unable to add shutdown hook: " + e);
            }
        }
    }