/*
 * Simple X11 interfacing routines
 * Header file
 *
 * $Id: xutil.h,v 1.12 2003/02/15 03:06:25 hsteoh Exp hsteoh $
 */

#ifndef XUTIL_H
#define XUTIL_H

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <list.h>			// NOTE: *MUST* be prog/lib version!!!

#include "event.h"


/* Note: fatal errors will cause exceptions to be thrown. */
class xwindow;				// forward decl
class xconnection {
  Display *disp;
  int scrn;				// screen number

  // Event loop integration
  eventloop *loop;			// [R]
  class eventcallback : public eventhandler {
    friend class xconnection;
    xconnection *conn;			// [R]

    eventcallback(xconnection *connection) : conn(connection) {}
    ~eventcallback() {}
    void read_ready(eventloop *src, int fd);
    void write_ready(eventloop *src, int fd);
  } event_cb;

  // Color-handling stuff
  int depth;				// screen depth
  Colormap cmap;			// application-wide colormap

  // Event-dispatching stuff
  elist<xwindow*> winlist;		// list of registered windows

  void dispatch_event(XEvent ev);	// handle single event
  void process_pending_event();		// wait for next event & process it
public:
  xconnection(char *xserver, eventloop *loop);	// ([R],[R])
  ~xconnection();

  // Access functions
  Display *display() { return disp; }
  int screen() { return scrn; }
  int scrn_depth() { return depth; }
  int server_socket() { return ConnectionNumber(disp); }

  // Convenience functions
  unsigned long black() { return BlackPixel(disp, scrn); }
  unsigned long white() { return WhitePixel(disp, scrn); }

  // Event-handling
  void register_window(xwindow *win);
  void unregister_window(xwindow *win);
};


/* Generic xwindow base class (mainly for registering with event loop) */
class xwindow {
  friend class xconnection;

  void update_attrs();			// update window attributes (wd, ht,
					// etc.)
protected:
  xconnection *conn;
  Window win;
  int wd, ht;				// current (internal) width/height
  int border_wd;			// current size of border
public:
  // Note: derived classes should call XSelectInput themselves; this base class
  // assumes nothing about what events are interesting
  xwindow(xconnection *conn, xwindow *parent, unsigned int x, unsigned int y,
          unsigned int width, unsigned int height, unsigned int border_width,
          unsigned long border_color, unsigned long bckgnd_color);
  virtual ~xwindow();

  // Access functions (these return actual dimensions in pixels)
  int width() { return wd; }
  int height() { return ht; }
  int ext_width() { return wd+border_wd*2; }	// external width of window
  int ext_height() { return ht+border_wd*2; }	// external height
  int border_width() { return border_wd; }

  // Generic hook to force windows to repaint themselves
  virtual void refresh();

  // This one is for the convenience of parent window dispatchers
  int operator== (Window w) { return win==w; }

  // Event dispatcher for window. Subclasses generally won't need to override
  // this, since they can just override the individual event handlers. This
  // method will invoke the individual event handlers based on the event type.
  // Note that subclasses still have to call XSelectInput() if they want to
  // actually receive any of these events. (This class does not call
  // XSelectInput() automatically.)
  virtual void handle_event(XEvent ev);

  // By default, these do nothing. Subclasses should override these to do
  // something sensible.
  virtual void expose(XExposeEvent ev);
  virtual void focus_in(XFocusInEvent ev);
  virtual void focus_out(XFocusOutEvent ev);
  virtual void key_press(XKeyPressedEvent ev);
  virtual void key_release(XKeyReleasedEvent ev);
  virtual void mouse_buttondown(XButtonPressedEvent ev);
  virtual void mouse_buttonup(XButtonReleasedEvent ev);
  virtual void mouse_enter(XEnterWindowEvent ev);
  virtual void mouse_leave(XLeaveWindowEvent ev);
  virtual void mouse_move(XMotionEvent ev);
};

/* Simple window class designed to be used by single-window applications.
 * A lot of stuff should give reasonable simple defaults; the application
 * itself should subclass this class to provide app-specific functions.
 */
class appwindow : public xwindow {
protected:
  Display *disp;			// [R] (for convenience only)
public:
  appwindow(xconnection *conn,
            char *win_name, char *icon_name,
            int width, int height,
            char *resource_class, char *resource_name);
  ~appwindow();
};


/* Tiled background handling stuff */
class tiled_bckgnd {
  xconnection *conn;			// [R]
  Drawable d;				// drawable to draw on

  Pixmap tile;
  GC tilegc;
public:
  // FIXME: should use generic image loader
  tiled_bckgnd(xconnection *conn, Drawable d, char *xpmfile);
  ~tiled_bckgnd();

  void paint(int x, int y, int w, int h);
};

#endif // XUTIL_H
