#include "config.h"

#include "yxapp.h"

#include "yfull.h"

#include "wmprog.h"
#include "wmmgr.h"
#include "MwmUtil.h"
#include "prefs.h"
#include "yprefs.h"
#include "ypixbuf.h"
#include "yconfig.h"

#include <sys/resource.h>
#include <stdlib.h>

#include "intl.h"

YXApplication *xapp = 0;

YDesktop *desktop = 0;
XContext windowContext;

YCursor YXApplication::leftPointer;
YCursor YXApplication::rightPointer;
YCursor YXApplication::movePointer;

Atom _XA_WM_CHANGE_STATE;
Atom _XA_WM_CLASS;
Atom _XA_WM_CLIENT_LEADER;
Atom _XA_WM_CLIENT_MACHINE;
Atom _XA_WM_COLORMAP_NOTIFY;
Atom _XA_WM_COLORMAP_WINDOWS;
Atom _XA_WM_COMMAND;
Atom _XA_WM_DELETE_WINDOW;
Atom _XA_WM_DESKTOP;
Atom _XA_WM_HINTS;
Atom _XA_WM_ICON_NAME;
Atom _XA_WM_ICON_SIZE;
Atom _XA_WM_LOCALE_NAME;
Atom _XA_WM_NAME;
Atom _XA_WM_NORMAL_HINTS;
Atom _XA_WM_PROTOCOLS;
Atom _XA_WM_SIZE_HINTS;
Atom _XA_WM_STATE;
Atom _XA_WM_TAKE_FOCUS;
Atom _XA_WM_TRANSIENT_FOR;
Atom _XA_WM_WINDOW_ROLE;
Atom _XA_WM_ZOOM_HINTS;

Atom _XATOM_MWM_HINTS;
//Atom _XA_MOTIF_WM_INFO;!!!
Atom _XA_WINDOW_ROLE;
Atom _XA_SM_CLIENT_ID;
Atom _XA_ICEWM_ACTION;
Atom _XA_CLIPBOARD;
Atom _XA_TARGETS;
Atom _XA_XEMBED_INFO;
Atom _XA_UTF8_STRING;

Atom _XA_WIN_APP_STATE;
Atom _XA_WIN_AREA_COUNT;
Atom _XA_WIN_AREA;
Atom _XA_WIN_CLIENT_LIST;
Atom _XA_WIN_DESKTOP_BUTTON_PROXY;
Atom _XA_WIN_EXPANDED_SIZE;
Atom _XA_WIN_HINTS;
Atom _XA_WIN_ICONS;
Atom _XA_WIN_LAYER;
Atom _XA_WIN_PROTOCOLS;
Atom _XA_WIN_STATE;
Atom _XA_WIN_SUPPORTING_WM_CHECK;
#ifdef CONFIG_TRAY
Atom _XA_WIN_TRAY;
#endif
Atom _XA_WIN_WORKAREA;
Atom _XA_WIN_WORKSPACE_COUNT;
Atom _XA_WIN_WORKSPACE_NAMES;
Atom _XA_WIN_WORKSPACE;

Atom _XA_NET_ACTIVE_WINDOW;
Atom _XA_NET_CLIENT_LIST;
Atom _XA_NET_CLIENT_LIST_STACKING;
Atom _XA_NET_CLOSE_WINDOW;
Atom _XA_NET_CURRENT_DESKTOP;
Atom _XA_NET_DESKTOP_GEOMETRY;
Atom _XA_NET_DESKTOP_LAYOUT;
Atom _XA_NET_DESKTOP_NAMES;
Atom _XA_NET_DESKTOP_VIEWPORT;
Atom _XA_NET_FRAME_EXTENTS;
Atom _XA_NET_MOVERESIZE_WINDOW;
Atom _XA_NET_NUMBER_OF_DESKTOPS;
Atom _XA_NET_PROPERTIES;
Atom _XA_NET_REQUEST_FRAME_EXTENTS;
Atom _XA_NET_RESTACK_WINDOW;
Atom _XA_NET_SHOWING_DESKTOP;
Atom _XA_NET_STARTUP_ID;
Atom _XA_NET_STARTUP_INFO_BEGIN;
Atom _XA_NET_STARTUP_INFO;
Atom _XA_NET_SUPPORTED;
Atom _XA_NET_SUPPORTING_WM_CHECK;
Atom _XA_NET_SYSTEM_TRAY_MESSAGE_DATA;
Atom _XA_NET_SYSTEM_TRAY_OPCODE;
Atom _XA_NET_SYSTEM_TRAY_ORIENTATION;
Atom _XA_NET_SYSTEM_TRAY_VISUAL;
Atom _XA_NET_VIRTUAL_ROOTS;
Atom _XA_NET_WM_ACTION_ABOVE;
Atom _XA_NET_WM_ACTION_BELOW;
Atom _XA_NET_WM_ACTION_CHANGE_DESKTOP;
Atom _XA_NET_WM_ACTION_CLOSE;
Atom _XA_NET_WM_ACTION_FULLSCREEN;
Atom _XA_NET_WM_ACTION_MAXIMIZE_HORZ;
Atom _XA_NET_WM_ACTION_MAXIMIZE_VERT;
Atom _XA_NET_WM_ACTION_MINIMIZE;
Atom _XA_NET_WM_ACTION_MOVE;
Atom _XA_NET_WM_ACTION_RESIZE;
Atom _XA_NET_WM_ACTION_SHADE;
Atom _XA_NET_WM_ACTION_STICK;
Atom _XA_NET_WM_ALLOWED_ACTIONS;
Atom _XA_NET_WM_BYPASS_COMPOSITOR;
Atom _XA_NET_WM_DESKTOP;
Atom _XA_NET_WM_FULL_PLACEMENT;
Atom _XA_NET_WM_FULLSCREEN_MONITORS;
Atom _XA_NET_WM_HANDLED_ICONS;
Atom _XA_NET_WM_ICON_GEOMETRY;
Atom _XA_NET_WM_ICON_NAME;
Atom _XA_NET_WM_ICON;
Atom _XA_NET_WM_MOVERESIZE;
Atom _XA_NET_WM_NAME;
Atom _XA_NET_WM_OPAQUE_REGION;
Atom _XA_NET_WM_PID;
Atom _XA_NET_WM_PING;
Atom _XA_NET_WM_STATE;
Atom _XA_NET_WM_STATE_ABOVE;
Atom _XA_NET_WM_STATE_BELOW;
Atom _XA_NET_WM_STATE_DEMANDS_ATTENTION;
Atom _XA_NET_WM_STATE_FOCUSED;
Atom _XA_NET_WM_STATE_FULLSCREEN;
Atom _XA_NET_WM_STATE_HIDDEN;
Atom _XA_NET_WM_STATE_MAXIMIZED_HORZ;
Atom _XA_NET_WM_STATE_MAXIMIZED_VERT;
Atom _XA_NET_WM_STATE_MODAL;
Atom _XA_NET_WM_STATE_SHADED;
Atom _XA_NET_WM_STATE_SKIP_PAGER;
Atom _XA_NET_WM_STATE_SKIP_TASKBAR;
Atom _XA_NET_WM_STATE_STICKY;
Atom _XA_NET_WM_STRUT;
Atom _XA_NET_WM_STRUT_PARTIAL;
Atom _XA_NET_WM_SYNC_REQUEST;
Atom _XA_NET_WM_SYNC_REQUEST_COUNTER;
Atom _XA_NET_WM_USER_TIME;
Atom _XA_NET_WM_USER_TIME_WINDOW;
Atom _XA_NET_WM_VISIBLE_ICON_NAME;
Atom _XA_NET_WM_VISIBLE_NAME;
Atom _XA_NET_WM_WINDOW_OPACITY;
Atom _XA_NET_WM_WINDOW_TYPE;
Atom _XA_NET_WM_WINDOW_TYPE_COMBO;
Atom _XA_NET_WM_WINDOW_TYPE_DESKTOP;
Atom _XA_NET_WM_WINDOW_TYPE_DIALOG;
Atom _XA_NET_WM_WINDOW_TYPE_DND;
Atom _XA_NET_WM_WINDOW_TYPE_DOCK;
Atom _XA_NET_WM_WINDOW_TYPE_DROPDOWN_MENU;
Atom _XA_NET_WM_WINDOW_TYPE_MENU;
Atom _XA_NET_WM_WINDOW_TYPE_NORMAL;
Atom _XA_NET_WM_WINDOW_TYPE_NOTIFICATION;
Atom _XA_NET_WM_WINDOW_TYPE_POPUP_MENU;
Atom _XA_NET_WM_WINDOW_TYPE_SPLASH;
Atom _XA_NET_WM_WINDOW_TYPE_TOOLBAR;
Atom _XA_NET_WM_WINDOW_TYPE_TOOLTIP;
Atom _XA_NET_WM_WINDOW_TYPE_UTILITY;
Atom _XA_NET_WORKAREA;

Atom _XA_KWM_DOCKWINDOW;
Atom _XA_KWM_WIN_ICON;

Atom _XA_KDE_NET_SYSTEM_TRAY_WINDOWS;
Atom _XA_KDE_NET_WM_FRAME_STRUT;
Atom _XA_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR;
Atom _XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE;
Atom _XA_KDE_SPLASH_PROGRESS;
Atom _XA_KDE_WM_CHANGE_STATE;

Atom XA_XdndAware;
Atom XA_XdndDrop;
Atom XA_XdndEnter;
Atom XA_XdndFinished;
Atom XA_XdndLeave;
Atom XA_XdndPosition;
Atom XA_XdndProxy;
Atom XA_XdndStatus;

YColor *YColor::black(NULL);
YColor *YColor::white(NULL);

ref<YPixmap> buttonIPixmap;
ref<YPixmap> buttonAPixmap;

ref<YPixmap> logoutPixmap;
ref<YPixmap> switchbackPixmap;
ref<YPixmap> listbackPixmap;
ref<YPixmap> dialogbackPixmap;

ref<YPixmap> menubackPixmap;
ref<YPixmap> menusepPixmap;
ref<YPixmap> menuselPixmap;

#ifdef CONFIG_GRADIENTS
ref<YImage> buttonIPixbuf;
ref<YImage> buttonAPixbuf;

ref<YImage> logoutPixbuf;
ref<YImage> switchbackPixbuf;
ref<YImage> listbackPixbuf;
ref<YImage> dialogbackPixbuf;

ref<YImage> menubackPixbuf;
ref<YImage> menuselPixbuf;
ref<YImage> menusepPixbuf;
#endif

//changed robc
ref<YPixmap> closePixmap[3];
ref<YPixmap> minimizePixmap[3];
ref<YPixmap> maximizePixmap[3];
ref<YPixmap> restorePixmap[3];
ref<YPixmap> hidePixmap[3];
ref<YPixmap> rollupPixmap[3];
ref<YPixmap> rolldownPixmap[3];
ref<YPixmap> depthPixmap[3];

#ifdef CONFIG_SHAPE
int shapesSupported;
int shapeEventBase, shapeErrorBase;
#endif

#ifdef CONFIG_XRANDR
int xrandrSupported;
bool xrandr12 = false;
int xrandrEventBase, xrandrErrorBase;
#endif

#ifdef DEBUG
int xeventcount = 0;
#endif

class YClipboard: public YWindow {
public:
    YClipboard(): YWindow() {
        fLen = 0;
        fData = 0;
    }
    ~YClipboard() {
        if (fData)
            delete [] fData;
        fData = 0;
        fLen = 0;
    }

    void setData(const char *data, int len) {
        if (fData)
            delete [] fData;
        fLen = len;
        fData = new char[len];
        if (fData)
            memcpy(fData, data, len);
        if (fLen == 0)
            clearSelection(false);
        else
            acquireSelection(false);
    }
    void handleSelectionClear(const XSelectionClearEvent &clear) {
        if (clear.selection == _XA_CLIPBOARD) {
            if (fData)
                delete [] fData;
            fLen = 0;
            fData = 0;
        }
    }
    void handleSelectionRequest(const XSelectionRequestEvent &request) {
        if (request.selection == _XA_CLIPBOARD) {
            XSelectionEvent notify;

            notify.type = SelectionNotify;
            notify.requestor = request.requestor;
            notify.selection = request.selection;
            notify.target = request.target;
            notify.time = request.time;
            notify.property = request.property;

            if (request.selection == _XA_CLIPBOARD &&
                request.target == XA_STRING &&
                fLen > 0)
            {
                XChangeProperty(xapp->display(),
                                request.requestor,
                                request.property,
                                request.target,
                                8, PropModeReplace,
                                (unsigned char *)(fData ? fData : ""),
                                fLen);
            } else if (request.selection == _XA_CLIPBOARD &&
                       request.target == _XA_TARGETS &&
                       fLen > 0)
            {
                Atom type = XA_STRING;

                XChangeProperty(xapp->display(),
                                request.requestor,
                                request.property,
                                request.target,
                                32, PropModeReplace,
                                (unsigned char *)&type, 1);
            } else {
                notify.property = None;
            }

            XSendEvent(xapp->display(), notify.requestor, False, 0L, (XEvent *)&notify);
        }
    }

private:
    int fLen;
    char *fData;
};


static void initAtoms() {
    struct {
        Atom *atom;
        const char *name;
    } atom_info[] = {
        { &_XA_WM_CHANGE_STATE                  , "WM_CHANGE_STATE"                     },
        { &_XA_WM_CLASS                         , "WM_CLASS"                            },
        { &_XA_WM_CLIENT_LEADER                 , "WM_CLIENT_LEADER"                    },
        { &_XA_WM_CLIENT_MACHINE                , "WM_CLIENT_MACHINE"                   },
        { &_XA_WM_COLORMAP_NOTIFY               , "WM_COLORMAP_NOTIFY"                  },
        { &_XA_WM_COLORMAP_WINDOWS              , "WM_COLORMAP_WINDOWS"                 },
        { &_XA_WM_COMMAND                       , "WM_COMMAND"                          },
        { &_XA_WM_DELETE_WINDOW                 , "WM_DELETE_WINDOW"                    },
        { &_XA_WM_DESKTOP                       , "WM_DESKTOP"                          },
        { &_XA_WM_HINTS                         , "WM_HINTS"                            },
        { &_XA_WM_ICON_NAME                     , "WM_ICON_NAME"                        },
        { &_XA_WM_ICON_SIZE                     , "WM_ICON_SIZE"                        },
        { &_XA_WM_LOCALE_NAME                   , "WM_LOCALE_NAME"                      },
        { &_XA_WM_NAME                          , "WM_NAME"                             },
        { &_XA_WM_NORMAL_HINTS                  , "WM_NORMAL_HINTS"                     },
        { &_XA_WM_PROTOCOLS                     , "WM_PROTOCOLS"                        },
        { &_XA_WM_SIZE_HINTS                    , "WM_SIZE_HINTS"                       },
        { &_XA_WM_STATE                         , "WM_STATE"                            },
        { &_XA_WM_TAKE_FOCUS                    , "WM_TAKE_FOCUS"                       },
        { &_XA_WM_TRANSIENT_FOR                 , "WM_TRANSIENT_FOR"                    },
        { &_XA_WM_WINDOW_ROLE                   , "WM_WINDOW_ROLE"                      },
        { &_XA_WM_ZOOM_HINTS                    , "WM_ZOOM_HINTS"                       },

        { &_XA_WINDOW_ROLE                      , "WINDOW_ROLE"                         },
        { &_XA_SM_CLIENT_ID                     , "SM_CLIENT_ID"                        },
        { &_XA_ICEWM_ACTION                     , "_ICEWM_ACTION"                       },
        { &_XATOM_MWM_HINTS                     , _XA_MOTIF_WM_HINTS                    },

        { &_XA_KWM_DOCKWINDOW                   , "KWM_DOCKWINDOW"                      },
        { &_XA_KWM_WIN_ICON                     , "KWM_WIN_ICON"                        },

        { &_XA_KDE_NET_SYSTEM_TRAY_WINDOWS      , "_KDE_NET_SYSTEM_TRAY_WINDOWS"        },
        { &_XA_KDE_NET_WM_FRAME_STRUT           , "_KDE_NET_WM_FRAME_STRUT"             },
        { &_XA_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR"  },
        { &_XA_KDE_NET_WM_WINDOW_TYPE_OVERRIDE  , "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE"    },
        { &_XA_KDE_SPLASH_PROGRESS              , "_KDE_SPLASH_PROGRESS"                },
        { &_XA_KDE_WM_CHANGE_STATE              , "_KDE_WM_CHANGE_STATE"                },

        { &_XA_WIN_APP_STATE                    , XA_WIN_APP_STATE                      },
        { &_XA_WIN_AREA_COUNT                   , XA_WIN_AREA_COUNT                     },
        { &_XA_WIN_AREA                         , XA_WIN_AREA                           },
        { &_XA_WIN_CLIENT_LIST                  , XA_WIN_CLIENT_LIST                    },
        { &_XA_WIN_DESKTOP_BUTTON_PROXY         , XA_WIN_DESKTOP_BUTTON_PROXY           },
        { &_XA_WIN_EXPANDED_SIZE                , XA_WIN_EXPANDED_SIZE                  },
        { &_XA_WIN_HINTS                        , XA_WIN_HINTS                          },
        { &_XA_WIN_ICONS                        , XA_WIN_ICONS                          },
        { &_XA_WIN_LAYER                        , XA_WIN_LAYER                          },
        { &_XA_WIN_PROTOCOLS                    , XA_WIN_PROTOCOLS                      },
        { &_XA_WIN_STATE                        , XA_WIN_STATE                          },
        { &_XA_WIN_SUPPORTING_WM_CHECK          , XA_WIN_SUPPORTING_WM_CHECK            },
#ifdef CONFIG_TRAY
        { &_XA_WIN_TRAY                         , XA_WIN_TRAY                           },
#endif
        { &_XA_WIN_WORKAREA                     , XA_WIN_WORKAREA                       },
        { &_XA_WIN_WORKSPACE_COUNT              , XA_WIN_WORKSPACE_COUNT                },
        { &_XA_WIN_WORKSPACE_NAMES              , XA_WIN_WORKSPACE_NAMES                },
        { &_XA_WIN_WORKSPACE                    , XA_WIN_WORKSPACE                      },

        { &_XA_NET_ACTIVE_WINDOW                , "_NET_ACTIVE_WINDOW"                  },
        { &_XA_NET_CLIENT_LIST                  , "_NET_CLIENT_LIST"                    },
        { &_XA_NET_CLIENT_LIST_STACKING         , "_NET_CLIENT_LIST_STACKING"           },
        { &_XA_NET_CLOSE_WINDOW                 , "_NET_CLOSE_WINDOW"                   },
        { &_XA_NET_CURRENT_DESKTOP              , "_NET_CURRENT_DESKTOP"                },
        { &_XA_NET_DESKTOP_GEOMETRY             , "_NET_DESKTOP_GEOMETRY"               },
        { &_XA_NET_DESKTOP_LAYOUT               , "_NET_DESKTOP_LAYOUT"                 },
        { &_XA_NET_DESKTOP_NAMES                , "_NET_DESKTOP_NAMES"                  },
        { &_XA_NET_DESKTOP_VIEWPORT             , "_NET_DESKTOP_VIEWPORT"               },
        { &_XA_NET_FRAME_EXTENTS                , "_NET_FRAME_EXTENTS"                  },
        { &_XA_NET_MOVERESIZE_WINDOW            , "_NET_MOVERESIZE_WINDOW"              },
        { &_XA_NET_NUMBER_OF_DESKTOPS           , "_NET_NUMBER_OF_DESKTOPS"             },
        { &_XA_NET_PROPERTIES                   , "_NET_PROPERTIES"                     },
        { &_XA_NET_REQUEST_FRAME_EXTENTS        , "_NET_REQUEST_FRAME_EXTENTS"          },
        { &_XA_NET_RESTACK_WINDOW               , "_NET_RESTACK_WINDOW"                 },
        { &_XA_NET_SHOWING_DESKTOP              , "_NET_SHOWING_DESKTOP"                },
        { &_XA_NET_STARTUP_ID                   , "_NET_STARTUP_ID"                     },
        { &_XA_NET_STARTUP_INFO                 , "_NET_STARTUP_INFO"                   },
        { &_XA_NET_STARTUP_INFO_BEGIN           , "_NET_STARTUP_INFO_BEGIN"             },
        { &_XA_NET_SUPPORTED                    , "_NET_SUPPORTED"                      },
        { &_XA_NET_SUPPORTING_WM_CHECK          , "_NET_SUPPORTING_WM_CHECK"            },
        { &_XA_NET_SYSTEM_TRAY_MESSAGE_DATA     , "_NET_SYSTEM_TRAY_MESSAGE_DATA"       },
        { &_XA_NET_SYSTEM_TRAY_OPCODE           , "_NET_SYSTEM_TRAY_OPCODE"             },
        { &_XA_NET_SYSTEM_TRAY_ORIENTATION      , "_NET_SYSTEM_TRAY_ORIENTATION"        },
        { &_XA_NET_SYSTEM_TRAY_VISUAL           , "_NET_SYSTEM_TRAY_VISUAL"             },
        { &_XA_NET_VIRTUAL_ROOTS                , "_NET_VIRTUAL_ROOTS"                  },
        { &_XA_NET_WM_ACTION_ABOVE              , "_NET_WM_ACTION_ABOVE"                },
        { &_XA_NET_WM_ACTION_BELOW              , "_NET_WM_ACTION_BELOW"                },
        { &_XA_NET_WM_ACTION_CHANGE_DESKTOP     , "_NET_WM_ACTION_CHANGE_DESKTOP"       },
        { &_XA_NET_WM_ACTION_CLOSE              , "_NET_WM_ACTION_CLOSE"                },
        { &_XA_NET_WM_ACTION_FULLSCREEN         , "_NET_WM_ACTION_FULLSCREEN"           },
        { &_XA_NET_WM_ACTION_MAXIMIZE_HORZ      , "_NET_WM_ACTION_MAXIMIZE_HORZ"        },
        { &_XA_NET_WM_ACTION_MAXIMIZE_VERT      , "_NET_WM_ACTION_MAXIMIZE_VERT"        },
        { &_XA_NET_WM_ACTION_MINIMIZE           , "_NET_WM_ACTION_MINIMIZE"             },
        { &_XA_NET_WM_ACTION_MOVE               , "_NET_WM_ACTION_MOVE"                 },
        { &_XA_NET_WM_ACTION_RESIZE             , "_NET_WM_ACTION_RESIZE"               },
        { &_XA_NET_WM_ACTION_SHADE              , "_NET_WM_ACTION_SHADE"                },
        { &_XA_NET_WM_ACTION_STICK              , "_NET_WM_ACTION_STICK"                },
        { &_XA_NET_WM_ALLOWED_ACTIONS           , "_NET_WM_ALLOWED_ACTIONS"             },
        { &_XA_NET_WM_BYPASS_COMPOSITOR         , "_NET_WM_BYPASS_COMPOSITOR"           },
        { &_XA_NET_WM_DESKTOP                   , "_NET_WM_DESKTOP"                     },
        { &_XA_NET_WM_FULL_PLACEMENT            , "_NET_WM_FULL_PLACEMENT"              },
        { &_XA_NET_WM_FULLSCREEN_MONITORS       , "_NET_WM_FULLSCREEN_MONITORS"         },
        { &_XA_NET_WM_HANDLED_ICONS             , "_NET_WM_HANDLED_ICONS"               },
        { &_XA_NET_WM_ICON_GEOMETRY             , "_NET_WM_ICON_GEOMETRY"               },
        { &_XA_NET_WM_ICON_NAME                 , "_NET_WM_ICON_NAME"                   },
        { &_XA_NET_WM_ICON                      , "_NET_WM_ICON"                        },
        { &_XA_NET_WM_MOVERESIZE                , "_NET_WM_MOVERESIZE"                  },
        { &_XA_NET_WM_NAME                      , "_NET_WM_NAME"                        },
        { &_XA_NET_WM_OPAQUE_REGION             , "_NET_WM_OPAQUE_REGION"               },
        { &_XA_NET_WM_PID                       , "_NET_WM_PID"                         },
        { &_XA_NET_WM_PING                      , "_NET_WM_PING"                        },
        { &_XA_NET_WM_STATE                     , "_NET_WM_STATE"                       },
        { &_XA_NET_WM_STATE_ABOVE               , "_NET_WM_STATE_ABOVE"                 },
        { &_XA_NET_WM_STATE_BELOW               , "_NET_WM_STATE_BELOW"                 },
        { &_XA_NET_WM_STATE_DEMANDS_ATTENTION   , "_NET_WM_STATE_DEMANDS_ATTENTION"     },
        { &_XA_NET_WM_STATE_FOCUSED             , "_NET_WM_STATE_FOCUSED"               },
        { &_XA_NET_WM_STATE_FULLSCREEN          , "_NET_WM_STATE_FULLSCREEN"            },
        { &_XA_NET_WM_STATE_HIDDEN              , "_NET_WM_STATE_HIDDEN"                },
        { &_XA_NET_WM_STATE_MAXIMIZED_HORZ      , "_NET_WM_STATE_MAXIMIZED_HORZ"        },
        { &_XA_NET_WM_STATE_MAXIMIZED_VERT      , "_NET_WM_STATE_MAXIMIZED_VERT"        },
        { &_XA_NET_WM_STATE_MODAL               , "_NET_WM_STATE_MODAL"                 },
        { &_XA_NET_WM_STATE_SHADED              , "_NET_WM_STATE_SHADED"                },
        { &_XA_NET_WM_STATE_SKIP_PAGER          , "_NET_WM_STATE_SKIP_PAGER"            },
        { &_XA_NET_WM_STATE_SKIP_TASKBAR        , "_NET_WM_STATE_SKIP_TASKBAR"          },
        { &_XA_NET_WM_STATE_STICKY              , "_NET_WM_STATE_STICKY"                },
        { &_XA_NET_WM_STRUT                     , "_NET_WM_STRUT"                       },
        { &_XA_NET_WM_STRUT_PARTIAL             , "_NET_WM_STRUT_PARTIAL"               },
        { &_XA_NET_WM_SYNC_REQUEST              , "_NET_WM_SYNC_REQUEST"                },
        { &_XA_NET_WM_SYNC_REQUEST_COUNTER      , "_NET_WM_SYNC_REQUEST_COUNTER"        },
        { &_XA_NET_WM_USER_TIME                 , "_NET_WM_USER_TIME"                   },
        { &_XA_NET_WM_USER_TIME_WINDOW          , "_NET_WM_USER_TIME_WINDOW"            },
        { &_XA_NET_WM_VISIBLE_ICON_NAME         , "_NET_WM_VISIBLE_ICON_NAME"           },
        { &_XA_NET_WM_VISIBLE_NAME              , "_NET_WM_VISIBLE_NAME"                },
        { &_XA_NET_WM_WINDOW_OPACITY            , "_NET_WM_WINDOW_OPACITY"              },
        { &_XA_NET_WM_WINDOW_TYPE               , "_NET_WM_WINDOW_TYPE"                 },
        { &_XA_NET_WM_WINDOW_TYPE_COMBO         , "_NET_WM_WINDOW_TYPE_COMBO"           },
        { &_XA_NET_WM_WINDOW_TYPE_DESKTOP       , "_NET_WM_WINDOW_TYPE_DESKTOP"         },
        { &_XA_NET_WM_WINDOW_TYPE_DIALOG        , "_NET_WM_WINDOW_TYPE_DIALOG"          },
        { &_XA_NET_WM_WINDOW_TYPE_DND           , "_NET_WM_WINDOW_TYPE_DND"             },
        { &_XA_NET_WM_WINDOW_TYPE_DOCK          , "_NET_WM_WINDOW_TYPE_DOCK"            },
        { &_XA_NET_WM_WINDOW_TYPE_DROPDOWN_MENU , "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU"   },
        { &_XA_NET_WM_WINDOW_TYPE_MENU          , "_NET_WM_WINDOW_TYPE_MENU"            },
        { &_XA_NET_WM_WINDOW_TYPE_NORMAL        , "_NET_WM_WINDOW_TYPE_NORMAL"          },
        { &_XA_NET_WM_WINDOW_TYPE_NOTIFICATION  , "_NET_WM_WINDOW_TYPE_NOTIFICATION"    },
        { &_XA_NET_WM_WINDOW_TYPE_POPUP_MENU    , "_NET_WM_WINDOW_TYPE_POPUP_MENU"      },
        { &_XA_NET_WM_WINDOW_TYPE_SPLASH        , "_NET_WM_WINDOW_TYPE_SPLASH"          },
        { &_XA_NET_WM_WINDOW_TYPE_TOOLBAR       , "_NET_WM_WINDOW_TYPE_TOOLBAR"         },
        { &_XA_NET_WM_WINDOW_TYPE_TOOLTIP       , "_NET_WM_WINDOW_TYPE_TOOLTIP"         },
        { &_XA_NET_WM_WINDOW_TYPE_UTILITY       , "_NET_WM_WINDOW_TYPE_UTILITY"         },
        { &_XA_NET_WORKAREA                     , "_NET_WORKAREA"                       },

        { &_XA_CLIPBOARD                        , "CLIPBOARD"                           },
        { &_XA_XEMBED_INFO                      , "_XEMBED_INFO"                        },
        { &_XA_TARGETS                          , "TARGETS"                             },
        { &_XA_UTF8_STRING                      , "UTF8_STRING"                         },

        { &XA_XdndAware                         , "XdndAware"                           },
        { &XA_XdndDrop                          , "XdndDrop"                            },
        { &XA_XdndEnter                         , "XdndEnter"                           },
        { &XA_XdndFinished                      , "XdndFinished"                        },
        { &XA_XdndLeave                         , "XdndLeave"                           },
        { &XA_XdndPosition                      , "XdndPosition"                        },
        { &XA_XdndProxy                         , "XdndProxy"                           },
        { &XA_XdndStatus                        , "XdndStatus"                          }
    };
    unsigned int i;

#ifdef HAVE_XINTERNATOMS
    const char *names[ACOUNT(atom_info)];
    Atom atoms[ACOUNT(atom_info)];

    for (i = 0; i < ACOUNT(atom_info); i++)
        names[i] = atom_info[i].name;

    XInternAtoms(xapp->display(), (char **)names, ACOUNT(atom_info), False, atoms);

    for (i = 0; i < ACOUNT(atom_info); i++)
        *(atom_info[i].atom) = atoms[i];
#else
    for (i = 0; i < ACOUNT(atom_info); i++)
        *(atom_info[i].atom) = XInternAtom(xapp->display(),
                                           atom_info[i].name, False);
#endif
}

static void initPointers() {
    YXApplication::leftPointer.load("left.xpm",  XC_left_ptr);
    YXApplication::rightPointer.load("right.xpm", XC_right_ptr);
    YXApplication::movePointer.load("move.xpm",  XC_fleur);
}

static void initColors() {
    YColor::black = new YColor("rgb:00/00/00");
    YColor::white = new YColor("rgb:FF/FF/FF");
}

void YXApplication::initModifiers() {
    XModifierKeymap *xmk = XGetModifierMapping(xapp->display());
    AltMask = MetaMask = WinMask = SuperMask = HyperMask =
        NumLockMask = ScrollLockMask = ModeSwitchMask = 0;
    
    if (xmk) {
        KeyCode *c = xmk->modifiermap;

        for (int m = 0; m < 8; m++)
            for (int k = 0; k < xmk->max_keypermod; k++, c++) {
                if (*c == NoSymbol)
                    continue;
                KeySym kc = XkbKeycodeToKeysym(xapp->display(), *c, 0, 0);
                if (kc == NoSymbol)
                    kc = XkbKeycodeToKeysym(xapp->display(), *c, 0, 1);
                if (kc == XK_Num_Lock && NumLockMask == 0)
                    NumLockMask = (1 << m);
                if (kc == XK_Scroll_Lock && ScrollLockMask == 0)
                    ScrollLockMask = (1 << m);
                if ((kc == XK_Alt_L || kc == XK_Alt_R) && AltMask == 0)
                    AltMask = (1 << m);
                if ((kc == XK_Meta_L || kc == XK_Meta_R) && MetaMask == 0)
                    MetaMask = (1 << m);
                if ((kc == XK_Super_L || kc == XK_Super_R) && SuperMask == 0)
                    SuperMask = (1 << m);
                if ((kc == XK_Hyper_L || kc == XK_Hyper_R) && HyperMask == 0)
                    HyperMask = (1 << m);
                if ((kc == XK_Mode_switch || kc == XK_ISO_Level3_Shift) && ModeSwitchMask == 0)
                    ModeSwitchMask = (1 << m);
            }

        XFreeModifiermap(xmk);
    }
    if (MetaMask == AltMask)
        MetaMask = 0;

    MSG(("alt:%d meta:%d super:%d hyper:%d mode:%d num:%d scroll:%d",
         AltMask, MetaMask, SuperMask, HyperMask, ModeSwitchMask,
         NumLockMask, ScrollLockMask));

    // some hacks for "broken" modifier configurations
    if (HyperMask == SuperMask)
        HyperMask = 0;

    // this basically does what <0.9.13 versions did
    if (AltMask != 0 && MetaMask == Mod1Mask) {
        MetaMask = AltMask;
        AltMask = Mod1Mask;
    }

    if (AltMask == 0 && MetaMask != 0) {
        if (MetaMask != Mod1Mask) {
            AltMask = Mod1Mask;
        }
        else {
            AltMask = MetaMask;
            MetaMask = 0;
        }
    }

    if (AltMask == 0)
        AltMask = Mod1Mask;

    if (ModeSwitchMask & (AltMask | MetaMask | SuperMask | HyperMask))
        ModeSwitchMask = 0;

    PRECONDITION(xapp->AltMask != 0);
    PRECONDITION(xapp->AltMask != ShiftMask);
    PRECONDITION(xapp->AltMask != ControlMask);
    PRECONDITION(xapp->AltMask != xapp->MetaMask);

    KeyMask =
        ControlMask |
        ShiftMask |
        AltMask |
        MetaMask |
        SuperMask |
        HyperMask |
        ModeSwitchMask;

    ButtonMask =
        Button1Mask |
        Button2Mask |
        Button3Mask |
        Button4Mask |
        Button5Mask;

    ButtonKeyMask = KeyMask | ButtonMask;

#if 0
    KeySym wl = XKeycodeToKeysym(app->display(), 115, 0);
    KeySym wr = XKeycodeToKeysym(app->display(), 116, 0);

    if (wl == XK_Super_L) {
    } else if (wl == XK_Meta_L) {
    }
#endif
    // this will do for now, but we should actualy check the keycodes
    Win_L = Win_R = 0;

    if (SuperMask != 0) {
        WinMask = SuperMask;

        Win_L = XK_Super_L;
        Win_R = XK_Super_R;
    }
    MSG(("alt:%d meta:%d super:%d hyper:%d win:%d mode:%d num:%d scroll:%d",
         AltMask, MetaMask, SuperMask, HyperMask, WinMask, ModeSwitchMask,
         NumLockMask, ScrollLockMask));

}

void YXApplication::dispatchEvent(YWindow *win, XEvent &xev) {
    if (xev.type == KeyPress || xev.type == KeyRelease) {
        YWindow *w = win;

        if (!(fGrabWindow != 0 && !fGrabTree)) {
            if (w->toplevel())
                w = w->toplevel();

            if (w->getFocusWindow() != 0)
                w = w->getFocusWindow();
        }

        while (w && (w->handleKey(xev.xkey) == false)) {
            if (fGrabTree && w == fXGrabWindow)
                break;
            w = w->parent();
        }
    } else {
        Window child;

        if (xev.type == MotionNotify) {
            if (xev.xmotion.window != win->handle()) {
                if (XTranslateCoordinates(xapp->display(),
                                          xev.xany.window, win->handle(),
                                          xev.xmotion.x, xev.xmotion.y,
                                          &xev.xmotion.x, &xev.xmotion.y, &child) == True)
                    xev.xmotion.window = win->handle();
                else
                    return ;
            }
        } else if (xev.type == ButtonPress || xev.type == ButtonRelease ||
                   xev.type == EnterNotify || xev.type == LeaveNotify)
        {
            if (xev.xbutton.window != win->handle()) {
                if (XTranslateCoordinates(xapp->display(),
                                          xev.xany.window, win->handle(),
                                          xev.xbutton.x, xev.xbutton.y,
                                          &xev.xbutton.x, &xev.xbutton.y, &child) == True)
                    xev.xbutton.window = win->handle();
                else
                    return ;
            }
        } else if (xev.type == KeyPress || xev.type == KeyRelease) {
            if (xev.xkey.window != win->handle()) {
                if (XTranslateCoordinates(xapp->display(),
                                          xev.xany.window, win->handle(),
                                          xev.xkey.x, xev.xkey.y,
                                          &xev.xkey.x, &xev.xkey.y, &child) == True)
                    xev.xkey.window = win->handle();
                else
                    return ;
            }
        }
        win->handleEvent(xev);
    }
}

void YXApplication::handleGrabEvent(YWindow *winx, XEvent &xev) {
    union {
        YWindow *ptr;
        XPointer xptr;
    } win = { winx };

    PRECONDITION(win.ptr != 0);
    if (fGrabTree) {
        if (xev.xbutton.subwindow != None) {
            if (XFindContext(display(),
                         xev.xbutton.subwindow,
                         windowContext,
                             &(win.xptr)) != 0)
            {
                if (xev.type == EnterNotify || xev.type == LeaveNotify)
                    win.ptr = 0;
                else
                    win.ptr = fGrabWindow;
            }
        } else {
            if (XFindContext(display(),
                             xev.xbutton.window,
                             windowContext,
                             &(win.xptr)) != 0)
            {
                if (xev.type == EnterNotify || xev.type == LeaveNotify)
                    win.ptr = 0;
                else
                    win.ptr = fGrabWindow;
            }
        }
        if (win.ptr == 0)
            return ;
        {
            YWindow *p = win.ptr;
            while (p) {
                if (p == fXGrabWindow)
                    break;
                p = p->parent();
            }
            if (p == 0) {
                if (xev.type == EnterNotify || xev.type == LeaveNotify)
                    return ;
                else
                    win.ptr = fGrabWindow;
            }
        }
        if (xev.type == EnterNotify || xev.type == LeaveNotify)
            if (win.ptr != fGrabWindow)
                return ;
        if (fGrabWindow != fXGrabWindow)
            win.ptr = fGrabWindow;
    }
    dispatchEvent(win.ptr, xev);
}

void YXApplication::replayEvent() {
    if (!fReplayEvent) {
        fReplayEvent = true;
        XAllowEvents(xapp->display(), ReplayPointer, CurrentTime);
    }
}

void YXApplication::captureGrabEvents(YWindow *win) {
    if (fGrabWindow == fXGrabWindow && fGrabTree) {
        fGrabWindow = win;
    }
}

void YXApplication::releaseGrabEvents(YWindow *win) {
    if (win == fGrabWindow && fGrabTree) {
        fGrabWindow = fXGrabWindow;
    }
}

int YXApplication::grabEvents(YWindow *win, Cursor ptr, unsigned int eventMask, int grabMouse, int grabKeyboard, int grabTree) {
    int rc;

    if (fGrabWindow != 0)
        return 0;
    if (win == 0)
        return 0;

    XSync(display(), 0);
    fGrabTree = grabTree;
    if (grabMouse) {
        fGrabMouse = 1;
        rc = XGrabPointer(display(), win->handle(),
                          grabTree ? True : False,
                          eventMask,
                          GrabModeSync, GrabModeAsync,
                          None, ptr, CurrentTime);

        if (rc != Success) {
            MSG(("grab status = %d\x7", rc));
            return 0;
        }
    } else {
        fGrabMouse = 0;

        XChangeActivePointerGrab(display(),
                                 eventMask,
                                 ptr, CurrentTime);
    }

    if (grabKeyboard) {
        rc = XGrabKeyboard(display(), win->handle(),
                           ///False,
                           grabTree ? True : False,
                           GrabModeSync, GrabModeAsync, CurrentTime);
        if (rc != Success && grabMouse) {
            MSG(("grab status = %d\x7", rc));
            XUngrabPointer(display(), CurrentTime);
            return 0;
        }
    }
    XAllowEvents(xapp->display(), SyncPointer, CurrentTime);

    desktop->resetColormapFocus(false);

    fXGrabWindow = win;
    fGrabWindow = win;
    return 1;
}

int YXApplication::releaseEvents() {
    if (fGrabWindow == 0)
        return 0;
    fGrabWindow = 0;
    fXGrabWindow = 0;
    fGrabTree = 0;
    if (fGrabMouse) {
        XUngrabPointer(display(), CurrentTime);
        fGrabMouse = 0;
    }
    XUngrabKeyboard(display(), CurrentTime);
    desktop->resetColormapFocus(true);
    return 1;
}

void YXApplication::afterWindowEvent(XEvent & /*xev*/) {
}

bool YXApplication::filterEvent(const XEvent &xev) {
    if (xev.type == MappingNotify) {
        msg("MappingNotify");
        XMappingEvent xmapping = xev.xmapping;
        XRefreshKeyboardMapping(&xmapping);

        initModifiers();

        desktop->grabKeys();
        return true;
    }
    return false;
}

void YXApplication::saveEventTime(const XEvent &xev) {
    switch (xev.type) {
    case ButtonPress:
    case ButtonRelease:
        lastEventTime = xev.xbutton.time;
        break;

    case MotionNotify:
        lastEventTime = xev.xmotion.time;
        break;

    case KeyPress:
    case KeyRelease:
        lastEventTime = xev.xkey.time;
        break;

    case EnterNotify:
    case LeaveNotify:
        lastEventTime = xev.xcrossing.time;
        break;

    case PropertyNotify:
        lastEventTime = xev.xproperty.time;
        break;

    case SelectionClear:
        lastEventTime = xev.xselectionclear.time;
        break;

    case SelectionRequest:
        lastEventTime = xev.xselectionrequest.time;
        break;

    case SelectionNotify:
        lastEventTime = xev.xselection.time;
        break;
    }
}

Time YXApplication::getEventTime(const char */*debug*/) const {
    return lastEventTime;
}


extern void logEvent(const XEvent &xev);


bool YXApplication::hasColormap() {
    XVisualInfo pattern;
    pattern.screen = DefaultScreen(display());

    int nVisuals;
    bool rc = false;

    XVisualInfo *first_visual(XGetVisualInfo(display(), VisualScreenMask,
                                              &pattern, &nVisuals));
    XVisualInfo *visual = first_visual;

    while(visual && nVisuals--) {
        if (visual->c_class & 1)
            rc = true;
        visual++;
    }

    if (first_visual)
        XFree(first_visual);

    return rc;
}


void YXApplication::alert() {
    XBell(display(), 100);
}

void YXApplication::setClipboardText(const ustring &data) {
    if (fClip == 0)
        fClip = new YClipboard();
    if (!fClip)
        return ;
    cstring s(data);
    fClip->setData(s.c_str(), s.c_str_len());
}

YXApplication::YXApplication(int *argc, char ***argv, const char *displayName):
    YApplication(argc, argv)
{
    xapp = this;
    lastEventTime = CurrentTime;
    fGrabWindow = 0;
    fGrabTree = 0;
    fXGrabWindow = 0;
    fGrabMouse = 0;
    fPopup = 0;
    fClip = 0;
    fReplayEvent = false;

    bool runSynchronized(false);

    for (char ** arg = *argv + 1; arg < *argv + *argc; ++arg) {
        if (**arg == '-') {
            char *value;
            if (GetLongArgument(value, "display", arg, *argv+*argc))
            {
                displayName = value;
                continue;
            }
            else if (IS_LONG_SWITCH("sync"))
                runSynchronized = true;
        }
    }

    if (displayName == 0)
        displayName = getenv("DISPLAY");
    else {
        static char disp[256] = "DISPLAY=";
        strcat(disp, displayName);
        putenv(disp);
    }

    if (!(fDisplay = XOpenDisplay(displayName)))
        die(1, _("Can't open display: %s. X must be running and $DISPLAY set."),
            displayName ? displayName : _("<none>"));

    if (runSynchronized)
        XSynchronize(display(), True);

    xfd.registerPoll(this, ConnectionNumber(display()));

    windowContext = XUniqueContext();

    new YDesktop(0, RootWindow(display(), DefaultScreen(display())));
    extern void image_init();
    image_init();

    initAtoms();
    initModifiers();
    initPointers();
    initColors();

#ifdef CONFIG_SHAPE
    shapesSupported = XShapeQueryExtension(display(),
                                           &shapeEventBase, &shapeErrorBase);
#endif
#ifdef CONFIG_XRANDR
    xrandrSupported = XRRQueryExtension(display(),
                                        &xrandrEventBase, &xrandrErrorBase);
    {
        int major = 0;
        int minor = 0;
        XRRQueryVersion(display(), &major, &minor);
            
        MSG(("XRRVersion: %d %d", major, minor)); 
        if (major > 1 || (major == 1 && minor >= 2)) {
            xrandrSupported = 1;
            xrandr12 = true;
        }
    }
#endif
}

YXApplication::~YXApplication() {
    xfd.unregisterPoll();
    XCloseDisplay(display());
    fDisplay = 0;
    xapp = 0;
}

bool YXApplication::handleXEvents() {
    if (XPending(display()) > 0) {
        XEvent xev;

        XNextEvent(display(), &xev);
#ifdef DEBUG
        xeventcount++;
#endif
        //msg("%d", xev.type);

        saveEventTime(xev);

#ifdef DEBUG
        DBG logEvent(xev);
#endif
        if (filterEvent(xev)) {
            ;
        } else {
            int ge = (xev.type == ButtonPress ||
                      xev.type == ButtonRelease ||
                      xev.type == MotionNotify ||
                      xev.type == KeyPress ||
                      xev.type == KeyRelease /*||
                      xev.type == EnterNotify ||
                      xev.type == LeaveNotify*/) ? 1 : 0;

            fReplayEvent = false;

            if (fPopup && ge) {
                handleGrabEvent(fPopup, xev);
            } else if (fGrabWindow && ge) {
                handleGrabEvent(fGrabWindow, xev);
            } else {
                handleWindowEvent(xev.xany.window, xev);
            }
            if (fGrabWindow) {
                if (xev.type == ButtonPress || xev.type == ButtonRelease || xev.type == MotionNotify)
                {
                    if (!fReplayEvent) {
                        XAllowEvents(xapp->display(), SyncPointer, CurrentTime);
                    }
                }
            }
        }
        XFlush(display());
        return true;
    }
    return false;
}

bool YXApplication::handleIdle() {
    return handleXEvents();
}
 
void YXApplication::handleWindowEvent(Window xwindow, XEvent &xev) {
    int rc = 0;
    union {
        YWindow *ptr;
        XPointer xptr;
    } window = { 0 };

    if ((rc = XFindContext(display(),
                           xwindow,
                           windowContext,
                           &(window.xptr))) == 0)
    {
        if ((xev.type == KeyPress || xev.type == KeyRelease)
            && window.ptr->toplevel() != 0) 
        {
            YWindow *w = window.ptr;

            w = w->toplevel();

            if (w->getFocusWindow() != 0)
                w = w->getFocusWindow();

            dispatchEvent(w, xev);
        } else {
            window.ptr->handleEvent(xev);
        }
    } else {
        if (xev.type == MapRequest) {
            // !!! java seems to do this ugliness
            //YFrameWindow *f = getFrame(xev.xany.window);
            msg("APP BUG? mapRequest for window %lX sent to destroyed frame %lX!",
                xev.xmaprequest.parent,
                xev.xmaprequest.window);
            desktop->handleEvent(xev);
        } else if (xev.type == ConfigureRequest) {
            msg("APP BUG? configureRequest for window %lX sent to destroyed frame %lX!",
                xev.xmaprequest.parent,
                xev.xmaprequest.window);
            desktop->handleEvent(xev);
        } else if (xev.type != DestroyNotify) {
            MSG(("unknown window 0x%lX event=%d", xev.xany.window, xev.type));
        }
    }
    if (xev.type == KeyPress || xev.type == KeyRelease) ///!!!
        afterWindowEvent(xev);
}

void YXApplication::flushXEvents() {
    XSync(display(), False);
}

void YXPoll::notifyRead() {
    owner()->handleXEvents();
}

void YXPoll::notifyWrite() { }

bool YXPoll::forRead() {
    return true;
}

bool YXPoll::forWrite() { return false; }
