/* awindow.h
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2026 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef AWINDOW_H
#define AWINDOW_H

#include "aguixdefs.h"
#include "aguix.h"
#include "lowlevelfunc.h"
#include "text.h"
#include "request.h"
#include "acontainer.h"
#include "callback.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "widget.h"
#include <list>
#include <string>
#include <algorithm>

class AWindow : public Widget {
public:
  typedef enum { AWINDOW_NORMAL,
                 AWINDOW_DIALOG } wm_window_type_t;

  AWindow( AGUIX *parent,
           int x,
           int y,
           int width,
           int height,
           std::string title,
           wm_window_type_t type = AWINDOW_NORMAL );
  ~AWindow();
  AWindow( const AWindow &other );
  AWindow &operator=( const AWindow &other );

  Display *getDisplay() const;
  Window getWindow() const;
  Screen *getScreen() const;
  GC *getGC() const;
  AGUIX *getAGUIX() const;
  int setResizable(int state);
  void setMaxSize(int mwidth,int mheight);
  void setMinSize(int mwidth,int mheight);
  virtual void show();
  void show(Window);
  virtual void hide();
  void hide(Window);
  void minimize();
  void toFront();
  void move( int nx, int ny );
  void resize( int nw, int nh );
  virtual void sizeChanged( int width, int height, bool explicit_resize );
  void redraw();
  const char *getTitle() const;
  void setTitle( std::string new_title );
  int getBG() const;
  void setBG(int bg);
  void ReactMessage(Message *msg);
  bool handleMessage(XEvent *,Message *msg);
  void resizeSubWin(Window win,int w,int h);
  void moveSubWin(Window win,int x,int y);
  bool hasSubWin(Window win) const;
  Window getSubWindow(Window parent,int x,int y,int w,int h);
  void removeSubWin(Window subwin);
  bool isParent(Window childwin,bool) const;
  bool isParent( Window ) const;
  Widget *findWidgetForWindow( Window );
  void setCursor(int type);
  void unsetCursor();
  
  void invalidFocus();
  void applyFocus( Widget *newfocus );
  bool isOwner( Widget *f ) const;

  void maximizeX();
  void maximizeY();
  int getBorderWidth() const;
  void setBorderWidth( int nv );

  int addTextFromString( const char *text,
			 int tx,
			 int ty,
			 int vspace,
			 Text ***return_texts,
			 int *return_count,
			 int *return_y );
  int addMultiLineText( const std::string text,
                        AContainer &ac,
                        int xpos, int ypos,
                        AContainer **return_container,
                        std::list<Text*> *return_text_list,
                        bool split_on_newline = false );
  void centerScreen();
  bool contains( Widget *elem ) const;
  Widget *getFocusOwner() const;
  void nextFocus();
  void prevFocus();
  void setDoTabCycling( bool nv );
  bool getDoTabCycling() const;
  bool isTopParent( Window childwin );
  bool isVisible() const;
  void useStippleBackground();
  void forbidUserInput();
  void permitUserInput();
  bool getForbidInput() const;
  void setTransientForAWindow( const AWindow *twin = NULL );
#ifdef USE_XIM
  XIC getXIC() const;
  int createXIC();
  void closeXIC();
  void XICdestroyed();
#endif
  bool isTopLevel() const;
  int request( const char *reqtitle,
               const char *text,
               const char *buttons,
               Requester::request_flags_t flags = Requester::REQUEST_NONE );
  int request( const char *reqtitle,
               const char *text,
               const std::vector< std::vector< std::pair< std::string, int > > > &button_rows,
               Requester::request_flags_t flags = Requester::REQUEST_NONE );
  int string_request( const char *reqtitle,
                      const char *lines,
                      const char *default_str,
                      const char *buttons,
                      char **return_str,
                      Requester::request_flags_t flags = Requester::REQUEST_NONE );
  int string_request( const char *reqtitle,
                      const char *lines,
                      const char *default_str,
                      const char *buttons,
                      char **return_str,
                      Requester::request_flags_t flags,
                      const Requester::request_options &options );
  int getMapNr() const;
  AContainer *setContainer( AContainer *newcont, bool autoResize = false );
  void removeContainer( AContainer *cont );
  void removeFromContainer( Widget *twid );

  void contMaximize( bool applyMinSize = false, bool applyMaxSize = false, bool grow_only = false );
  void updateCont();

  template <class T> T *add( T *w )
  {
      std::list<Widget*>::iterator it1;
  
      if ( w == NULL ) return NULL;
  
      it1 = std::find( _childs.begin(), _childs.end(), w );
      if ( it1 != _childs.end() ) return NULL;
  
      if ( w->setParent( this ) != 0 ) return NULL;
      _childs.push_back( w );
      if ( _created == true ) w->create();
      return w;
  }
  void remove( Widget *w );
  void destroy();
  int create();

  int addWindowEvent( Window subwin, long mask );

  int getMinWidth() const;
  int getMinHeight() const;
  int getMaxWidth() const;
  int getMaxHeight() const;

  static const int KEYCB_WHENVISIBLE = 1;

  void addKeyCallBack( CallBack *new_cb, int mode = 0 );
  void removeKeyCallBack( CallBack *cb );

  void forbidCallBacks();
  void permitCallBacks();
  bool callBackForbidden() const;
  int isMaximized();

  int getRootPosition( int *x,
                       int *y );
  void forceOpenPosition( int x, int y,
                          bool max_h,
                          bool max_v );

  void enableXDND();
  bool acceptXDND();

  Widget *findWidgetForRootPos( int rx, int ry );

  void setOverrideRedirect();
protected:
  bool onScreen;
  int _bg;
  int maxw,maxh,minw,minh;

  int m_open_pos_x, m_open_pos_y;
  bool m_open_max_h, m_open_max_v;
  bool m_force_open_position;
  
  Window win;
  std::list<Window> subwins;
  int border;

  bool doTabCycling;
  int forbidinput;
#ifdef USE_XIM
  XIC inputcontext;
#endif
  Requester *req;

  XSizeHints *m_size_hints;
  
  int mapNr;
  AContainer *container;
  bool contAutoResize;
  int msgW, msgH;
  void doCreateStuff();
  void doDestroyStuff();
  int setParent( class AWindow *parent );
  int setWMTitle();
  const std::list<Widget*> &getChilds() const;

  typedef enum { SEARCH_WIDGET, SEARCH_NEXT, SEARCH_FINISHED } focus_search_mode_t;
  int searchNextFocus( focus_search_mode_t &search_mode,
		       const Widget *element,
		       Widget **new_element,
		       Widget **prev_element = NULL );
public:
  Widget *searchNextFocus( const Widget *current );
  Widget *searchPrevFocus( const Widget *current );
private:
  std::list<Widget*> _childs;
  typedef std::list<Widget*>::iterator childs_it;
  typedef std::list<Widget*>::const_iterator childs_const_it;
  std::string _title;

  typedef struct {
    CallBack *cb;
    AWindow *subwin;
    int mode;
  } key_listener_t;
  std::list<key_listener_t> key_listener;

  void addKeyCallBack( AWindow *subwin, CallBack *new_cb, int mode = 0 );
  void removeKeyCallBack( AWindow *subwin, CallBack *cb );
  Window findWindowForRootPos( int rx, int ry );
    void applyIcon();

  bool _callback_forbidden;
  wm_window_type_t m_window_type;
  bool m_enable_xdnd;
};

#endif
