//
// WindowManager.hh for pekwm
// Copyright (C) 2003-2025 Claes Nästén <pekdon@gmail.com>
//
// windowmanager.hh for aewm++
// Copyright (C) 2000 Frank Hale <frankhale@yahoo.com>
// http://sapphire.sourceforge.net/
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#ifndef _PEKWM_WINDOWMANAGER_HH_
#define _PEKWM_WINDOWMANAGER_HH_

#include "config.h"

#include "pekwm.hh"
#include "AppCtrl.hh"
#include "Client.hh"
#include "EventHandler.hh"
#include "EventLoop.hh"
#include "ManagerWindows.hh"

#include "Os.hh"
#include "tk/Action.hh"
#include "tk/PWinObj.hh"

#include <algorithm>
#include <map>

class WindowManager : public AppCtrl,
		      public EventLoop
{
public:
	static WindowManager *start(const std::string &bin_dir,
				    const std::string &config_file,
				    bool replace, bool skip_start,
				    bool synchronous, bool standalone);
	virtual ~WindowManager();

	void doEventLoop(void);

	// START - AppCtrl interface.
	virtual void reload(void) { _reload = true; }
	virtual void restart(void) { restart(""); }
	virtual void restart(std::string command);
	virtual void shutdown(void) { _shutdown = true; }
	// END - AppCtrl interface.

	inline bool shallRestart(void) const { return _restart; }
	inline const std::string &getRestartCommand(void) const {
		return _restart_command;
	}

	bool isEventHandler() const {
		return _event_handler != nullptr;
	}

	void setEventHandler(EventHandler *event_handler) {
		if (_event_handler) {
			delete _event_handler;
		}
		_event_handler = event_handler;
	}

	// public event handlers used when doing grabbed actions
	void handleKeyEvent(XKeyEvent *ev);
	void handleButtonPressEvent(XButtonEvent *ev);
	void handleButtonReleaseEvent(XButtonEvent *ev);

	bool setScale(double old_scale, double new_scale, bool reload=true);

protected:
	WindowManager(const std::string &bin_dir, Os *os, bool standalone);

	void handlePekwmCmd(XClientMessageEvent *ev);
	bool recvPekwmCmd(XClientMessageEvent *ev);

	void startBackground(const std::string& theme_dir,
			     const std::string& texture);
	void stopBackground();

	bool startSys();
	void stopSys();
	void writeSysCommand(const std::string &cmd);

private:
	void setupDisplay();
	void scanWindows(void);
	void execStartFile(bool skip_start);

	void handleSignals(void);

	void doReload(void);
	void doReloadConfig(bool &scale_changed);
	void doReloadTheme(bool force=false);
	void doReloadThemeDecors(void);
	void doReloadMouse(void);
	void doReloadKeygrabber(bool force=false);
	void doReloadAutoproperties(void);
	void doReloadHarbour(void);
	void doReloadResources(void);
	bool isResourcesChanged(void);

	void cleanup(void);

	// screen edge related
	void screenEdgeCreate(void);
	void screenEdgeResize(void);
	void screenEdgeMapUnmap(void);

	bool getEvent(XEvent &ev);
	void handleEvent(XEvent &ev);
	bool handleEventHandlerEvent(XEvent &ev);

	PWinObj *updateWoForFrameClick(XButtonEvent *ev, PWinObj *orig_wo);

	void handleMapRequestEvent(XMapRequestEvent *ev);
	void handleUnmapEvent(XUnmapEvent *ev);
	void handleDestroyWindowEvent(XDestroyWindowEvent *ev);

	void handleConfigureRequestEvent(XConfigureRequestEvent *ev);
	void handleClientMessageEvent(XClientMessageEvent *ev);
	void handleNetRestackWindow(XClientMessageEvent *ev);
	void handleNetRequestFrameExtents(Window win);

	void handleColormapEvent(XColormapEvent *ev);
	void handlePropertyEvent(XPropertyEvent *ev);
	void handleMappingEvent(XMappingEvent *ev);
	void handleExposeEvent(XExposeEvent *ev);

	void handleMotionEvent(XMotionEvent *ev);

	void handleEnterNotify(XCrossingEvent *ev);
	void handleLeaveNotify(XCrossingEvent *ev);
	void handleFocusInEvent(XFocusChangeEvent *ev);

	void handleKeyEventAction(XKeyEvent *ev, const ActionEvent *ae,
				  PWinObj *wo, PWinObj *wo_orig);

	void readDesktopNamesHint(void);

	// private methods for the hints
	void initHints(void);

	Client *createClient(Window window, bool is_new);
	void showDialog(const std::string &title, const std::string &msg);

protected:
	/** OS interface for process handling etc. */
	Os *_os;
	/** pekwm_cmd buffer for commands that do not fit in 20 bytes. */
	std::string _pekwm_cmd_buf;

private:
	std::string _bin_dir;
	bool _standalone;
	bool _shutdown; //!< Set to wheter we want to shutdown.
	bool _reload; //!< Set to wheter we want to reload.
	bool _restart;
	std::string _restart_command;
	std::string _bg_args;
	OsSelect *_select;
	/** PID of the pekwm_bg helper */
	pid_t _bg_pid;
	/** ChildProcess for the pekwm_sys helper */
	ChildProcess *_sys_process;

	EventHandler *_event_handler;

	EdgeWO *_screen_edges[4];

	/**
	 * If set to true, skip next enter event. Used in conjunction with
	 * PWinObj::setSkipEnterAfter to skip "leave" events caused by
	 * internal windows  such as status dialog.
	 */
	bool _skip_enter;
};

namespace pekwm
{
	WindowManager *windowManager();
}

#endif // _PEKWM_WINDOWMANAGER_HH_
