/**************************************************************************

    This file is part of Xclass95, a Win95-looking GUI toolkit.
    Copyright (C) 1996, 1997 David Barth, Hector Peraza.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

**************************************************************************/

#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <sys/time.h>
   
#include <xclass/utils.h>
#include <xclass/OXClient.h>
#include <xclass/OXFrame.h>
#include <xclass/OXTip.h>
#include <xclass/OLayout.h>


Time OXFrame::_lastclick = 0;
unsigned int OXFrame::_lastbutton = 0;
unsigned int OXFrame::_dbx = 0;
unsigned int OXFrame::_dby = 0;
unsigned int OXFrame::_dbw = 0;


//----------------------------------------------------------------

OXFrame::OXFrame(const OXWindow *p, int w, int h,
                 unsigned int options, unsigned long back) : 
  OXWindow(p, 0, 0, w, h, 0, CopyFromParent, CopyFromParent,
           CopyFromParent, 0, NULL) {

    XSetWindowAttributes wattr;
    unsigned long mask;

    _options = options;
    _w = w; _h = h; _x = _y = _bw = 0;

    if (_options & (SUNKEN_FRAME | RAISED_FRAME))
      _bw = (_options & DOUBLE_BORDER) ? 2 : 1;

    mask = CWBackPixel | CWEventMask;
    wattr.background_pixel = back;
    wattr.event_mask = ExposureMask;
    if (_options & MAIN_FRAME) {
      wattr.event_mask |= StructureNotifyMask;
      XChangeWindowAttributes(GetDisplay(), _id, mask, &wattr); 
/**/      if (_defaultBackgroundPicture)
/**/        SetBackgroundPixmap(_defaultBackgroundPicture->GetPicture());
    } else {
      XChangeWindowAttributes(GetDisplay(), _id, mask, &wattr); 
/**/      if (!(_options & OWN_BKGND))
/**/        SetBackgroundPixmap(ParentRelative);
    }

    _tip = NULL;
    _tip_text = NULL;
}

void OXFrame::ChangeOptions(unsigned int options) {

  if ((options & (DOUBLE_BORDER | SUNKEN_FRAME | RAISED_FRAME)) !=
      (_options & (DOUBLE_BORDER | SUNKEN_FRAME | RAISED_FRAME))) {
    if (options & (SUNKEN_FRAME | RAISED_FRAME))
      _bw = (options & DOUBLE_BORDER) ? 2 : 1;
    else
      _bw = 0;
  }

  _options = options;
}

void OXFrame::DrawBorder() {
  switch (_options & (SUNKEN_FRAME | RAISED_FRAME | DOUBLE_BORDER)) {
  case SUNKEN_FRAME:
    XDrawLine (GetDisplay(), _id, _shadowGC, 0, 0, _w-2, 0);
    XDrawLine (GetDisplay(), _id, _shadowGC, 0, 0, 0, _h-2);
    XDrawLine (GetDisplay(), _id, _hilightGC, 0, _h-1, _w-1, _h-1);
    XDrawLine (GetDisplay(), _id, _hilightGC, _w-1, _h-1, _w-1, 0);
    break;

  case SUNKEN_FRAME | DOUBLE_BORDER:
    XDrawLine (GetDisplay(), _id, _blackGC, 0, 0, _w-1, 0);
    XDrawLine (GetDisplay(), _id, _blackGC, 0, 0, 0, _h-1);
    XDrawLine (GetDisplay(), _id, _shadowGC, 1, 1, _w-3, 1);
    XDrawLine (GetDisplay(), _id, _shadowGC, 1, 1, 1, _h-3);

    XDrawLine (GetDisplay(), _id, _hilightGC, 1, _h-1, _w-1, _h-1);
    XDrawLine (GetDisplay(), _id, _hilightGC, _w-1, _h-1, _w-1, 1);
    XDrawLine (GetDisplay(), _id, _bckgndGC,  2, _h-2, _w-2, _h-2);
    XDrawLine (GetDisplay(), _id, _bckgndGC,  _w-2, 2, _w-2, _h-2);

    // 3-st button XDrawLine (GetDisplay(), _id, _hilightGC, 2, 2, _w-3, 2);
    break;

  case RAISED_FRAME:
    XDrawLine (GetDisplay(), _id, _hilightGC, 0, 0, _w-2, 0);
    XDrawLine (GetDisplay(), _id, _hilightGC, 0, 0, 0, _h-2);
    XDrawLine (GetDisplay(), _id, _shadowGC,  0, _h-1, _w-1, _h-1);
    XDrawLine (GetDisplay(), _id, _shadowGC,  _w-1, _h-1, _w-1, 0);
    break;

  case RAISED_FRAME | DOUBLE_BORDER:
    XDrawLine (GetDisplay(), _id, _hilightGC, 0, 0, _w-2, 0);
    XDrawLine (GetDisplay(), _id, _hilightGC, 0, 0, 0, _h-2);
    XDrawLine (GetDisplay(), _id, _bckgndGC, 1, 1, _w-3, 1);
    XDrawLine (GetDisplay(), _id, _bckgndGC, 1, 1, 1, _h-3);
    
    XDrawLine (GetDisplay(), _id, _shadowGC,  1, _h-2, _w-2, _h-2);
    XDrawLine (GetDisplay(), _id, _shadowGC,  _w-2, _h-2, _w-2, 1);
    XDrawLine (GetDisplay(), _id, _blackGC, 0, _h-1, _w-1, _h-1);
    XDrawLine (GetDisplay(), _id, _blackGC, _w-1, _h-1, _w-1, 0);
    break;

  default: break;
  }
}

void OXFrame::_DoRedraw() {
//  XClearWindow(GetDisplay(), _id);
  XClearArea(GetDisplay(), _id, _bw, _bw, _w - (_bw << 1), _h - (_bw << 1), False);
  // border will only be drawn if we have a 3D option hint
  // (RAISED_FRAME or SUNKEN_FRAME)
  DrawBorder();
}

int OXFrame::HandleConfigureNotify(XConfigureEvent *event) {
  // this generated some oscillations...
  // Resize(event->width, event->height);
  // ...do this instead:
  if ((event->width != _w) || (event->height != _h)) {
    _w = event->width;
    _h = event->height;
    Layout();
  }
  return True;
}

int OXFrame::HandleEvent(XEvent *event) {

  switch (event->xany.type) {

  case Expose:
    HandleExpose((XExposeEvent *)event);
    break;
  
  case GraphicsExpose:
    HandleGraphicsExpose((XGraphicsExposeEvent *)event);
    break;
  
  case ConfigureNotify:
    while (XCheckTypedWindowEvent(GetDisplay(), _id, ConfigureNotify, event));
    HandleConfigureNotify((XConfigureEvent *)event);
    break;

  case KeyPress:
  case KeyRelease:
    HandleKey((XKeyEvent *)event);
    break;
  
  case FocusIn:
  case FocusOut:
    HandleFocusChange((XFocusChangeEvent *)event);
    break;

  case ButtonPress:
    {
      int dbl_clk = False;

      if ((event->xbutton.time - _lastclick < 350) &&
          (event->xbutton.button == _lastbutton) &&
          (abs(event->xbutton.x_root - _dbx) < 3) &&
          (abs(event->xbutton.y_root - _dby) < 3) &&
          (event->xbutton.window == _dbw)) dbl_clk = True;

      _lastclick = event->xbutton.time;
      _lastbutton = event->xbutton.button;
      _dbx = event->xbutton.x_root;
      _dby = event->xbutton.y_root;
      _dbw = event->xbutton.window;

      if (dbl_clk) {
        if (!HandleDoubleClick((XButtonEvent*)event))
          HandleButton((XButtonEvent*)event);
      } else {
        HandleButton((XButtonEvent*)event);
      }
    }
    break;

  case ButtonRelease:
    HandleButton((XButtonEvent*)event);
    break;

  case EnterNotify:
  case LeaveNotify:
    HandleCrossing((XCrossingEvent *)event);
    break;

  case MotionNotify:
    while (XCheckTypedWindowEvent(GetDisplay(), _id, PointerMotionMask, event));
    HandleMotion((XMotionEvent *)event);
    break;

  case ClientMessage:
    HandleClientMessage((XClientMessageEvent *) event);
    break;

  case SelectionNotify:
    HandleSelection((XSelectionEvent *) event);
    break;

  case SelectionRequest:
    HandleSelectionRequest((XSelectionRequestEvent *) event);
    break;

  case SelectionClear:
    HandleSelectionClear((XSelectionClearEvent *) event);
    break;

  case PropertyNotify:
    HandlePropertyChange((XPropertyEvent *) event);
    break;

  default:
    Debug(DBG_EVENT, "OXFrame: Unknown event %#x for window %#x\n",
          event->xany.type, _id);
    break;
  }

  return True;
}

void OXFrame::Move(int x, int y) {
  if (x != _x || y != _y) {
    OXWindow::Move(x, y);
    _x = x; _y = y;
  }
}

void OXFrame::Resize(int w, int h) {
  if (w != _w || h != _h) {
    OXWindow::Resize(w, h);
    _w = w; _h = h;
    Layout();
  }
}

void OXFrame::Resize(ODimension size) {
  Resize(size.w, size.h);
}

void OXFrame::MoveResize(int x, int y, int w, int h) {
  // we do it anyway as we don't know if it's only a move or only a resize
  OXWindow::MoveResize(x, y, w, h);
  _x = x; _y = y; _w = w; _h = h;
  Layout();
}

void OXFrame::SendMessage(const OXWindow *w, long msg, long parm1, long parm2) {
  XEvent event;

  if (w) {
    event.xany.type = ClientMessage;
    event.xclient.format = 32;
    event.xclient.message_type = _XCLASS_MESSAGE;

    event.xclient.window = w->GetId();
    event.xclient.data.l[0] = msg;
    event.xclient.data.l[1] = parm1;
    event.xclient.data.l[2] = parm2;
    event.xclient.data.l[3] = 0L;
    event.xclient.data.l[4] = 0L;

    XSendEvent(GetDisplay(), w->GetId(), False, None, &event);
  }
}

int OXFrame::HandleClientMessage(XClientMessageEvent *event) {

  if (event->message_type == _XCLASS_MESSAGE) {
    ProcessMessage(event->data.l[0], event->data.l[1], event->data.l[2]);
    return True;
  }

  return False;
}

int OXFrame::HandleCrossing(XCrossingEvent *event) {

  if (_tip) {
    if ((event->type == EnterNotify) && 
        (!(event->state & (Button1Mask | Button2Mask |
                           Button3Mask | Button4Mask | Button5Mask)))) {
      if (_client->GetTipStatus() == 2)
        ShowTip();
      _client->StartTip(this);
    } else {
      HideTip();
    }
    return True;
  } else
    return False;
}

int OXFrame::HandleButton(XButtonEvent *event) {
  if (_tip) {
    if (event->type == ButtonPress) {
      HideTip();
    }
    return True;
  } else
    return False;
}

void OXFrame::SetTip(char * text) {
  if (_tip) delete _tip;
  _tip = new OXTip(_client->GetRoot(), new OString(text));
  XSelectInput(GetDisplay(), _id, ExposureMask |
               EnterWindowMask | LeaveWindowMask); 
}

void OXFrame::RemoveTip() {
  if (_tip) delete _tip;
  _tip = NULL;
}

void OXFrame::ShowTip() {
  int x, y, dummy;
  Window wtarget;

  XTranslateCoordinates(GetDisplay(), _id, _tip->GetParent()->GetId(),
                        0, _h, &x, &y, &wtarget);
  _tip->Show(x-5, y+6);
}

void OXFrame::HideTip() {
  _tip->Hide();
  _client->StopTip(this);
}


//----------------------------------------------------------------

OXCompositeFrame::OXCompositeFrame(const OXWindow *p, int w, int h,
				   unsigned int options,
				   unsigned long back) : 
  OXFrame(p, w, h, options, back) {
    XSetWindowAttributes wattr;
    unsigned long mask;

    // by default
    _layoutManager = NULL;

    _flist = NULL;

    if (_options & HORIZONTAL_FRAME)
      SetLayoutManager(new OHorizontalLayout(this));
    else
      SetLayoutManager(new OVerticalLayout(this));
}

OXCompositeFrame::~OXCompositeFrame() {
  SListFrameElt *ptr = _flist, *next;

  while (ptr) {
    next = ptr->next;
//    delete ptr->frame;  // is it safe to do this here?
    delete ptr;
    ptr = next;
  }
  if (_layoutManager) delete _layoutManager;
//  DestroyWindow();      // is it safe to do this here?
}

void OXCompositeFrame::SetLayoutManager(OLayoutManager *l) {
  if (_layoutManager) delete _layoutManager;
  _layoutManager = l;
}

void OXCompositeFrame::ChangeOptions(unsigned int options) {

  OXFrame::ChangeOptions(options);

  if (options & HORIZONTAL_FRAME)
    SetLayoutManager(new OHorizontalLayout(this));
  else
    SetLayoutManager(new OVerticalLayout(this));

}

void OXCompositeFrame::AddFrame(OXFrame *f, OLayoutHints *l) {
  SListFrameElt *nw, *ptr;

  // See remarks in OXClient.cc
  nw = new SListFrameElt;
  nw->frame = f;
  nw->layout = l;
  nw->state = 1;
  nw->next = NULL;
  if (_flist != NULL) {
    for (ptr=_flist; ptr->next != NULL; ptr=ptr->next);
    ptr->next = nw;
  } else _flist = nw;
}

void OXCompositeFrame::RemoveFrame(OXFrame *f) {
  SListFrameElt *ptr, *ptr2;

  if (_flist == NULL) return;

  if (_flist->frame == f) {
    ptr = _flist;
    _flist = _flist->next;
    delete ptr;
  } else {
    for (ptr = _flist;
        (ptr->next != NULL) && (ptr->next->frame != f);
         ptr = ptr->next);
    if (ptr->next == NULL) return; // not found!
    ptr2 = ptr->next;
    ptr->next = ptr2->next;
    delete ptr2;
  }
}

//void OXCompositeFrame::Resize(int w, int h) {
//  if (w != _w || h != _h) {
//    OXFrame::Resize(w, h);
//    Layout();
//  }
//}

//void OXCompositeFrame::Resize(ODimension size) {
//  Resize(size.w, size.h);
//}

//void OXCompositeFrame::MoveResize(int x, int y, int w, int h) {
//  OXFrame::MoveResize(x, y, w, h);
//  Layout();
//}

void OXCompositeFrame::MapSubwindows() {
  //  OFrameListIterator i(_list);
  //  OXWindow::MapSubwindows();
  //  for (; !i.EOL(); i.Next())
  //    i.GetFrame()->MapSubwindows();
  SListFrameElt *ptr;

  OXWindow::MapSubwindows();
  for (ptr = _flist; ptr != NULL; ptr = ptr->next)
    ptr->frame->MapSubwindows();
}

void OXCompositeFrame::HideFrame(OXFrame *f) {
  //  OFrameListElt *e;
  //  if ((e = _list->GetElt(f)) != NULL) {
  //    e->SetState(0);
  //    f->UnmapWindow();
  //    Layout();
  //  }
  SListFrameElt *ptr;

  for (ptr=_flist; ptr != NULL; ptr=ptr->next) {
    if (ptr->frame == f) {
      ptr->state = 0;
      ptr->frame->UnmapWindow();
      Layout();
      break;
    }
  }
}

void OXCompositeFrame::ShowFrame(OXFrame *f) {
  //  OFrameListElt *e;
  //  if ((e = _list->GetElt(f)) != NULL) {
  //    e->SetState(1);
  //    f->MapWindow();
  //    Layout();
  //  }
  SListFrameElt *ptr;

  for (ptr=_flist; ptr != NULL; ptr=ptr->next) {
    if (ptr->frame == f) {
      ptr->state = 1;
      ptr->frame->MapWindow();
      Layout();
      break;
    }
  }
}

int OXCompositeFrame::GetState(OXFrame *f) const {
//  OFrameListElt *e;
//
//  if ((e = _list->GetElt(f)) != NULL)
//    return e->GetState();
//  return 0;
  SListFrameElt *ptr;

  for (ptr=_flist; ptr != NULL; ptr=ptr->next)
    if (ptr->frame == f)
      return ptr->state;

  return 0;
}

void OXCompositeFrame::Layout() {
  _layoutManager->Layout();
}

//----------------------------------------------------------------

OXMainFrame::OXMainFrame(const OXWindow *p, int w, int h,
                         unsigned long options) :
  OXCompositeFrame(p, w, h, options | MAIN_FRAME) {

    XSetWMProtocols(GetDisplay(), _id, &WM_DELETE_WINDOW, 1);
    _bindlist = new OXSList(GetDisplay(), "Key bindings");
} 

OXMainFrame::~OXMainFrame() {
  DestroyWindow();
  if (_bindlist) delete _bindlist;
}

int OXMainFrame::HandleKey(XKeyEvent *event) {
  OXSNode *e;
  OXFrame *w;

  if (event->type == KeyPress)
    XAutoRepeatOff(GetDisplay());
  else
    XAutoRepeatOn(GetDisplay());

  if (!_bindlist) return False;
  e = _bindlist->GetNode(event->keycode);
  if (!e) return False;
  w = (OXFrame *) e->data;
  return w->HandleKey(event);
}

int OXMainFrame::BindKey(const OXWindow *w, int keycode, int modifier) const {
  if (_bindlist)
    if (_bindlist->Add(keycode, (XPointer) w) != NULL) {
      XGrabKey(GetDisplay(), keycode, modifier, _id, True,
               GrabModeAsync, GrabModeAsync);
      return True;
    }
  return False;
}

void OXMainFrame::RemoveBind(const OXWindow *w, int keycode, int modifier) const {
  if (_bindlist) {
    _bindlist->Remove(keycode);
    XUngrabKey(GetDisplay(), keycode, modifier, _id);
  }
}

int OXMainFrame::HandleClientMessage(XClientMessageEvent *event) {

  int retc = OXCompositeFrame::HandleClientMessage(event);

  if ((event->format == 32) && (event->data.l[0] == WM_DELETE_WINDOW)) {
    CloseWindow();
    return True;
  }

  return retc;
}

// override this to intercept close

void OXMainFrame::CloseWindow() {
  DestroyWindow();
  delete _client;
  exit(0);
}

void OXMainFrame::SetWindowName(char *Name) {
  XTextProperty wname;

  if (XStringListToTextProperty(&Name, 1, &wname) == 0) {
    Debug(DBG_ERR, "OXMainFrame: Cannot allocate window name!\n");
    return;
  }
  XSetWMName(GetDisplay(), _id, &wname);
  XFree(wname.value);
}

void OXMainFrame::SetIconName(char *Name) {
  XTextProperty wname;

  if (XStringListToTextProperty(&Name, 1, &wname) == 0) {
    Debug(DBG_ERR, "OXMainFrame: Cannot allocate icon name!\n");
    return;
  }
  XSetWMIconName(GetDisplay(), _id, &wname);
  XFree(wname.value);
}

void OXMainFrame::SetClassHints(char *ClassName, char *ResourceName) {
  XClassHint class_hints;
 
  class_hints.res_class = ClassName;
  class_hints.res_name  = ResourceName;
  XSetClassHint(GetDisplay(), _id, &class_hints);
}


// Set decoration style for MWM-compatible wm (mwm, ncdwm, fvwm?).
// Shall we check first for the presence of MWM_RUNNING property?

void OXMainFrame::SetMWMHints(unsigned int value, unsigned int funcs, unsigned int input) {
  MWMHintsProperty prop;

  prop.decorations = value;
  prop.functions   = funcs;
  prop.inputMode   = input;
  prop.flags       = MWM_HINTS_DECORATIONS | 
                     MWM_HINTS_FUNCTIONS   |
                     MWM_HINTS_INPUT_MODE;

  XChangeProperty(GetDisplay(), _id, _MOTIF_WM_HINTS, _MOTIF_WM_HINTS, 32,
                  PropModeReplace, (unsigned char *)&prop, PROP_MWM_HINTS_ELEMENTS);
}

void OXMainFrame::SetWMPosition(int x, int y) {
  XSizeHints hints;

  hints.flags = USPosition | PPosition;
  hints.x = x;
  hints.y = y;

  XSetWMNormalHints(GetDisplay(), _id, &hints);
}

void OXMainFrame::SetWMSize(int w, int h) {
  XSizeHints hints;

  hints.flags = USSize | PSize | PBaseSize;
  hints.width = hints.base_width = w;
  hints.height = hints.base_height = h;

  XSetWMNormalHints(GetDisplay(), _id, &hints);
}

void OXMainFrame::SetWMSizeHints(int wmin, int hmin, int wmax, int hmax,
                                 int winc, int hinc) {
  XSizeHints hints;

  hints.flags = PMinSize | PMaxSize | PResizeInc;
  hints.min_width   = wmin;
  hints.max_width   = wmax;
  hints.min_height  = hmin;
  hints.max_height  = hmax;
  hints.width_inc   = winc;
  hints.height_inc  = hinc;

  XSetWMNormalHints(GetDisplay(), _id, &hints);
}

void OXMainFrame::SetWMState(int state) {
  XWMHints hints;

  hints.flags = StateHint;
  hints.initial_state = state;

  XSetWMHints(GetDisplay(), _id, &hints);
}

//----------------------------------------------------------------

// Override this to intercept close...

void OXTransientFrame::CloseWindow() {
  DestroyWindow();
}





//--------------------------------------------------------------------
// Work in progress...
//--------------------------------------------------------------------


//--------------------------------------------------------------------
// Object version of a frame container element
class OFrameListElt {
public:
  OFrameListElt(class OXFrame *f, class OLayoutHints *h)
  { _frame = f; _hints = h; _state = 1; }
  ~OFrameListElt() { delete _hints; } // do not delete the frame, since it can be used elsewhere
  int GetState() { return _state; }
  void SetState(int s) { _state = s; }

  friend class OFrameList;
  friend class OFrameListIterator;
  
protected:
  class OXFrame *_frame;
  class OLayoutHints *_hints;
  int _state;
  class OFrameListElt *_next;
};

//--------------------------------------------------------------------
// Container for a list of frames
class OFrameList {
protected:
  OFrameListElt *_flist;

public:
  OFrameList() { _flist = NULL; }
  ~OFrameList() {}
  
  void AddFrame(class OXFrame *frame, OLayoutHints *hints = NULL); // adds an element to the list
  void RemoveFrame(class OXFrame *frame); // removes a frame from the list
  OFrameListElt *GetElt(class OXFrame *f);
  friend class OFrameListIterator;
};

//--------------------------------------------------------------------
// Iterator for a List of frames
class OFrameListIterator {
public:
  OFrameListIterator(OFrameListElt *elt) { _elt = elt; }
  OFrameListIterator(class OFrameList *list) { _elt = list->_flist; }
  ~OFrameListIterator() {}

  void Next() { _elt = _elt->_next; }
  void Begin(OFrameList *l) { _elt = l->_flist; }
  int EOL() { return (_elt == NULL); } 
  class OXFrame *GetFrame() { return _elt->_frame; }
  OFrameListElt *GetElt() { return _elt; }
  class OLayoutHints *GetHints() { return _elt->_hints; }
  int GetState() { return _elt->_state; }
  void SetState(int s) { _elt->_state = s; }

  friend class OFrameList;
  
protected:
  OFrameListElt *_elt;
};



//--------------------------------------------------------------------
// (unused)
class OAbstractBorder {
public:
  OAbstractBorder(int options) { _options = options; }

  virtual void DrawBorder(class OXFrame *f) = 0;

protected:
  int _options;
};


//----------------------------------------------------------------
// adds an element to the list
void OFrameList::AddFrame(OXFrame *frame, OLayoutHints *hints) {
  OFrameListElt *nw, *ptr;
  
  nw = new OFrameListElt(frame, hints);
  nw->_next = NULL;
  if (_flist != NULL) {
    for (ptr=_flist; ptr->_next != NULL; ptr=ptr->_next);
    ptr->_next = nw;
  } else _flist = nw;
}

// removes an element from the list
void OFrameList::RemoveFrame(OXFrame *frame) {
  OFrameListElt *ptr, *prev;

  for (ptr=_flist, prev=NULL; ptr!=NULL; ptr=ptr->_next) {
    if (ptr->_frame == frame) {
      delete ptr->_frame;
      delete ptr->_hints;
      if (prev == NULL) // removing first frame
        _flist = ptr->_next;
      else
        prev->_next = ptr->_next;
      delete ptr;
      continue;
    } else 
      prev = ptr;
  }
}

OFrameListElt *OFrameList::GetElt(OXFrame *f) {
  OFrameListIterator i(this);

  for (; !i.EOL(); i.Next()) {
    if (i.GetFrame() == f) return i.GetElt();
  }
  return NULL;
}
