/* $Id: emelfm2.h 893 2008-05-20 09:42:51Z tpgww $

Copyright (C) 2003-2008 tooar <tooar@gmx.net>

This file is part of emelFM2.
emelFM2 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 3, or (at your option)
any later version.

emelFM2 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 emelFM2; see the file GPL. If not, contact the Free Software
Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef __EMELFM2_H__
#define __EMELFM2_H__
//see also: Makefile has build-time conditional #defines and compiler parameters
#define _GNU_SOURCE
//default 64-bit functions (handle files > 2GB) (also in Makefile)
#define _FILE_OFFSET_BITS 64
//some of the Makefile define's are transferred in this header
#include "build.h"

#include <sys/types.h>
//needed for various statbuf declarations
#include <sys/stat.h>
#include <limits.h>
//some general things ...
#include <stdio.h>
#include <stdlib.h>

//#define GTK_DISABLE_DEPRECATED see Makefile
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <gmodule.h>

#define GETTEXT_PACKAGE BINNAME
#include <glib/gi18n-lib.h>

//#define E2_ASSISTED see build.h
#ifdef E2_ASSISTED
# include <atk/atk.h>
#endif

#ifndef PRIu64
//for systems that don't define PRI??? macros
# if defined(__WORDSIZE) && __WORDSIZE == 64
#  define PRIu64 "lu"
# else
//guess
#  define PRIu64 "llu"
# endif
#endif

//include code valid only for gtk versions > 2.6, according to the
//version in use when compiling
//#define E2_CURRENTGTK_VERSION see makefile and build.h
//mechanism for using glib/gtk facilities > min standard (2.6.0)
#ifdef E2_CURRENTGTK_VERSION
#if GLIB_CHECK_VERSION (2,8,0)
#define USE_GLIB2_8
#endif
#if GLIB_CHECK_VERSION (2,10,0)
#define USE_GLIB2_10
#endif
#if GLIB_CHECK_VERSION (2,12,0)
#define USE_GLIB2_12
#endif
#if GLIB_CHECK_VERSION (2,14,0)
#define USE_GLIB2_14
#endif
#if GTK_CHECK_VERSION (2,8,0)
#define USE_GTK2_8
#endif
#if GTK_CHECK_VERSION (2,10,0)
#define USE_GTK2_10
#endif
#if GTK_CHECK_VERSION (2,12,0)
#define USE_GTK2_12
# endif
#if GTK_CHECK_VERSION (2,14,0)
#define USE_GTK2_14
#endif
#endif

#ifdef USE_GTK2_12
//this token governs use of gtk 2.12 tooltips
#define USE_GTK2_12TIPS
//this token governs use of gtk 2.12 notebook-tab DnD
#define USE_GTK2_12DND
#endif

//tag for development of on-demand status-bar updates
//NOTE need to check all BGL effects
//#define E2_STATUS_DEMAND
#ifndef E2_STATUS_DEMAND
//tag for refcounting enable/disable status-bar updates
//#define E2_STATUS_REF
//allow checking for status-in progess when updating filelists
//#define E2_STATUS_BLOCK
#endif

//include error-message code regardless of debug state
//#define DEBUG_MESSAGES_ALWAYS

//setup for kernel-based file monitoring, as opposed to fam/gamin
//see Makefile & build.h for definition of these variables
#if defined(E2_FAM_INOTIFY) || defined(E2_FAM_DNOTIFY) || defined(E2_FAM_KQUEUE) || defined(E2_FAM_PORTEVENT)
# define E2_FAM_KERNEL
//this is needed too
# define E2_FAM
#else
//include code for file-change detection using FAM or gamin
//#define E2_FAM see Makefile & build.h
# ifdef E2_FAM
#  include <fam.h>
# endif
#endif
#ifdef E2_FAM
//usec interval after file events before FAM is polled
//needs to be long enough for most/all changes to be noticed
//by the monitor, but not so long that the user perceives a delay
#define E2_FAMWAIT 100000
#endif

//include code for making incremental changes to
//file lists, instead of dump & refill
//DOES NOT WORK
//#define E2_INCLIST

#define E2_BLOCK
#define E2_UNBLOCK

//include debug messages about refreshing
//#define E2_REFRESH_DEBUG
//include debug messages about mkdir dialog shutdown
//#define RACE_CHECK

//#ifndef USE_GTK2_10
//flag for code which enables something like the pre-0.1 approach to selecting
//items by dragging
//for gtk >= 2.10, this could be done by rubber-banding, but that's not so flexible
#define E2_ALTLEFTMOUSE
//#endif

//bytes, NOT characters this is a linux define
//#define NAME_MAX 255
//length of various buffers
#define E2_MAX_LEN 1024
//msec interval between pane-directory polls
//NOTE that the actual refresh interval may be a multiple (up to 3) times this
//to avoid too many refreshes during e.g. archive creation
#define E2_FILESCHECK_INTERVAL 1000
#define E2_FILESCHECK_INTERVAL_S 1
//msec interval between config-directory polls
//this is only used if E2_FAM not defined
#define E2_CONFIGCHECK_INTERVAL 5000
#define E2_CONFIGCHECK_INTERVAL_S 5
//msec interval between status line updates
#define E2_STATUSREPORT_INTERVAL 1500

//allowed msec interval between clicks to be treated as a double
//if gtk's value is smaller, then it is set to this instead
#define E2_CLICKINTERVAL 330

//padding for various widgets
#define E2_PADDING_LARGE 8
#define E2_PADDING 5
#define E2_PADDING_SMALL 3
#define E2_PADDING_XSMALL 2

#define E2_COMMAND_PREFIX "."G_DIR_SEPARATOR_S
#define PLUGIN action_labels[14]
// in these, "home" is a pointer determined at runtime
#define E2_CONFIG_DIR home,"."BINNAME
//#define E2_TRASH_DIR E2_CONFIG_DIR, "Trash"
//#define SYSTEM_TRASH_DIR home, ".Trash"
//#define E2_CONFIG_FILE "config"  no good for gettext ?? do not translate

//default build with horizontal panes - see Makefile
//#define E2_PANES_HORIZONTAL
//default icon pointsize - see Makefile
//#define E2IP "24"

//enable config/button/menu image-cacheing
#define E2_IMAGECACHE

//multi-colored filelists
#define E2_RAINBOW

#ifdef E2_RAINBOW
//no. of color values in each allocated block of memory
#define ATOMSPERCHUNK 10
typedef struct _E2_ColorData
{
	GMemChunk *chunk;	//data structure for a block of ATOMSPERCHUNK GdkColor structs
	GdkColor **pointers;	//allocated space for ATOMSPERCHUNK pointers
} E2_ColorData;
#endif

//maybe useful for multi-processor optimisation ?
//#define VOLATILE volatile
#define VOLATILE

//support key.alias action
//#define E2_KEYALIAS
//support addition of items to tree options (eg keybindings)
//#define E2_TRANSIENTKEYS see Makefile for this
#ifdef E2_TRANSIENTKEYS
# ifndef E2_KEYALIAS
#  define E2_KEYALIAS
# endif
#endif
//support addition of treestore iters from strings like 1.2.3
//#define E2_TREEINCREMENT

//support mountpoint-related capabilities
#define E2_FS_MOUNTABLE

//support detachable tabs for gtk >= 2.10
#ifdef USE_GTK2_10
#define E2_TABS_DETACH
#endif

//use replacement command-running (see Makefile)
//NOT FINISHED
//#ifndef E2_NEW_COMMAND
//#define E2_NEW_COMMAND
//#endif

//enable filesystem-tree-navigation dialogs
#define E2_TREEDIALOG

//support app-specific window translucence NOT WORKING FOR gtk < 2.12
//anyhow, good enough for the window-manager to do this equally for all apps
//#define E2_COMPOSIT see Makefile
#ifdef E2_COMPOSIT
# ifdef USE_GTK2_12
//minimum opacity % for dialogs
#  define DIALOG_OPACITY_LEVEL 95
# else
#  undef E2_COMPOSIT
# endif
#endif

//support vfs for file/dir processing
//NOT FINISHED
//needs cacheing of view data, backend data structs, history, marks
//lib interrogation, task backends etc etc
//#define E2_VFS see Makefile
//transition management
#ifdef E2_VFS
//# define E2_VFSTMP
# ifdef E2_VFSTMP
#  define E2_VFSTMPOK
# endif
#endif

//enable filelist liststore copying instead of getting fresh data from source
#ifdef E2_VFS
#define STORECOPY
#endif

//support for custom error handling with vfs
#ifdef E2_VFS
# define E2_ERR_NAME __sys_err
# define E2_ERR_INIT __sys_err = NULL;
# define E2_ERR_DECLARE GError *__sys_err = NULL;
# define E2_ERR_CLEARBACKUP(a) if (a != NULL) g_error_free (a);
//in these, there should never be any "a", we just need to get the leading comma
# define E2_ERR_NONE(a) a, NULL
# define E2_ERR_ARG(a) a, GError **__sys_err
# define E2_ERR_SAMEARG(a) a, __sys_err
# define E2_ERR_PTR(a) a, &__sys_err
# define E2_ERR_MSGC(a) a, (*__sys_err)->message
//these are for GError *, not for GError **
# define E2_ERR_MSGL(a) a, __sys_err->message
# define E2_ERR_IS(num) (__sys_err != NULL && __sys_err->code == num)
# define E2_ERR_ISNOT(num) (__sys_err == NULL || __sys_err->code != num)
//these are for use in a func with GError ** argument
# define E2_ERR_PIS(num) (__sys_err != NULL && (*__sys_err)->code == num)
# define E2_ERR_PISNOT(num) (__sys_err == NULL || (*__sys_err)->code != num)
# define E2_ERR_BACKUP(a) GError *a = NULL;if (__sys_err == NULL) __sys_err = &a;
# define E2_ERR_CLEAR if (__sys_err != NULL) { g_error_free (__sys_err); __sys_err = NULL; }
#else
# define E2_ERR_NAME
# define E2_ERR_INIT
# define E2_ERR_DECLARE
# define E2_ERR_CLEARBACKUP(a)
# define E2_ERR_NONE(a)
# define E2_ERR_PTR(a)
# define E2_ERR_ARG(a)
# define E2_ERR_SAMEARG(a)
# define E2_ERR_MSGC(a)
# define E2_ERR_MSGL(a)
# define E2_ERR_IS(num) (errno==num)
# define E2_ERR_ISNOT(num) (errno!=num)
# define E2_ERR_PIS(num) (errno==num)
# define E2_ERR_PISNOT(num) (errno!=num)
# define E2_ERR_CLEAR
# define E2_ERR_BACKUP(a)
#endif

//support for tailored argument(s) for fs functions
#ifdef E2_VFS
# define VPATH vpath
# define VPCSTR(p) *((const gchar**)p)
# define VPSTR(p) *((gchar**)p)
#else
# define VPATH const gchar
# define VPCSTR(p) p
# define VPSTR(p) (gchar*)p
#endif

//type of "dir" in a pane
typedef enum
{
	FS_LOCAL   = 0,		//default, mounted-local dir
	FS_FUSE    = 1,		//virtual local dir that needs special handling
	FS_REMOTE  = 1 << 1,//virtual non-mounted remote dir
	FS_ARCHIVE = 1 << 2,//archive (can be local or remote)
	FS_KERNEL  = 1 << 3,//a namespace in a multi-space local filesystem
	FS_SYNTH   = 1 << 4,//a synthesised virtual dir e.g. from a search process or metadata derived
} E2_FSType;
//types of virtual dir that are non-native, and warrant timeout if misbehaved
#define FS_SLOW (FS_FUSE | FS_REMOTE | FS_ARCHIVE)

#ifdef E2_VFS

typedef enum { E2PLACE_UNMOUNTED, E2PLACE_MOUNTING, E2PLACE_MOUNTED } PlaceReady;
typedef struct _E2_PlaceInfo
{
	gchar *priv_name; /* for mounted dir NULL CHECKME synth dir
	   for remote site escaped utf8, no trailer, login-ready URI before the filepath proper with p/w etc
	   for archive localised absolute path, with trailer, of temp dir used for unpacking whole or part
	   constructed from vtab data (not stored there, it may have P/W text in URI)
	*/
	gchar *tip; /* for mounted dir: NULL CHECKME synth dir
	   for remote site: utf8, no trailer, public components of 1st part of URI, before the filepath proper
	   for archive: utf8, no trailer, pseudo-path of archive, with all ancestor(s) including remote URI and other archive
	*/
	gchar *plain_pw;	//edit-ready password, utf8, or NULL if no P/W
	gchar *alias;	//user-friendly short-form utf8 for menu label etc, NULL or "" if not in use
	gchar *workplace;	//path of local fs dir, absolute localised no trailer
	E2_FSType dirtype;	//flags for type of namespace this is
//UNUSED	E2_FSHandler handler;	//enumerator of lib/plugin which handles fs-operations for this space
									//CHECK could be op-specific
//UNUSED	E2_VFSOpFlags cando;	//flags for the sorts of operations that can be performed
	PlaceReady mountstate;	//this place has been initialised by its backend handler
						//(maybe redundant if only mounted places can have a PlaceInfo)
	gboolean monitored;	//alteration monitoring in effect for this place (even if just polling)
	//directory histories for this namespace
	GList *pane1_entered; //pane 1 dirline history, specific to current namespace
	GList *pane2_entered; //pane 2 dirline history, specific to current namespace
	GList *pane1_history; //pane1 dir_history, but specific to this namespace
	GList *pane2_history; //pane2 dir_history, but specific to this namespace
	GList *pane1_visited; //pane1 visited, opendirs, but specific to this namespace
	GList *pane2_visited; //pane2 visited, opendirs, but specific to this namespace

	struct _E2_PlaceInfo* parentplace;	//for cd .. past root
	//etc
} PlaceInfo;

//data for vfs operations uning path-argument(s)
typedef struct _E2_Vpath
{
	const gchar *localpath; /*first, so that vpath* == gchar **
						typically an absolute path string
						encoding may actually be utf-8 if a handler lib
						requires that */
	PlaceInfo *spacedata;
//	GError *err; //replacement for error args in fs functions
} vpath;
#endif

#include "debug.h"
#include "e2_pane.h"
#include "e2_fileview.h"
#include "e2_alias.h"
#include "e2_bookmark.h"
#include "e2_button.h"
#include "e2_cache.h"
#include "e2_cl_option.h"
#include "e2_combobox.h"
#include "e2_command.h"
#include "e2_command_line.h"
#include "e2_fs.h"
#include "e2_hook.h"
#include "e2_keybinding.h"
#include "e2_list.h"
#include "e2_menu.h"
#include "e2_output.h"
#include "e2_toolbar.h"
#include "e2_tree.h"
#include "e2_utf8.h"
#include "e2_utils.h"
#include "e2_widget.h"
#include "e2_window.h"

// some nice helper/utility macros
//these 2 must both be called with BGL closed
//the gtk-versions block until at least one event is processed
//#define WAIT_FOR_EVENTS while (gtk_events_pending ()) { gtk_main_iteration (); }
//#define WAIT_FOR_EVENTS_SLOWLY while (gtk_events_pending ()) { gtk_main_iteration ();usleep(5000); }
#define WAIT_FOR_EVENTS gdk_threads_leave (); \
	while (g_main_context_pending (NULL)) { g_main_context_iteration (NULL, TRUE); } \
	gdk_threads_enter ();
#define WAIT_FOR_EVENTS_SLOWLY gdk_threads_leave (); \
	while (g_main_context_pending (NULL)) { g_main_context_iteration (NULL, TRUE); usleep(5000); } \
	gdk_threads_enter ();
//and these 2 are the corresponding ones with BGL open
#define WAIT_FOR_EVENTS_UNLOCKED while (g_main_context_pending (NULL)) { g_main_context_iteration (NULL, TRUE); }
#define WAIT_FOR_EVENTS_UNLOCKED_SLOWLY while (g_main_context_pending (NULL)) { g_main_context_iteration (NULL, TRUE); usleep(5000); }

#define ITEM_ISHIDDEN(expr) (expr[0]=='.')
//#define ITEM_ISHIDDEN(expr) (*expr=='.')

// development-phase string tagger
// search for _I( for general strings that need attention
#define _I(d) d

#define RUN_ONCE_CHECK(ret) \
	static gboolean run_once_check_init = FALSE; \
	if (run_once_check_init) \
		return ret; \
	else \
		run_once_check_init = TRUE;

// TEMP_FAILURE_RETRY for systems which do not have it
//uses errno so is valid for local operations only
#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(expr) \
    ({ glong _res; \
       do _res = (glong) (expr); while (_res == -1L && errno == EINTR); \
       _res; })
#endif

//do not implement slices everywhere until session-end cleanups are coded
//#ifdef USE_GLIB2_10
#if 0
# define ALLOCATE0(type) (type *) g_slice_alloc0 (sizeof (type));
# define ALLOCATE(type) (type *) g_slice_alloc (sizeof (type));
# define DEALLOCATE(type,ptr) g_slice_free1 (sizeof (type), ptr);
#else
# ifdef USE_GLIB2_8
#  define ALLOCATE0(type) (type *) g_try_malloc0 (sizeof (type));
# else
#  define ALLOCATE0(type) (type *) calloc (1, sizeof (type));
# endif
# define ALLOCATE(type) (type *) g_try_malloc (sizeof (type));
# define DEALLOCATE(type,ptr) g_free (ptr);
#endif
//for ALLOCATE's that are too small for a slice
#ifdef USE_GLIB2_8
# define MALLOCATE0(type) (type *) g_try_malloc0 (sizeof (type));
#else
# define MALLOCATE0(type) (type *) calloc (1, sizeof (type));
#endif
#define MALLOCATE(type) (type *) g_try_malloc (sizeof (type));
#define DEMALLOCATE(type,ptr) g_free (ptr);

#ifdef USE_GLIB2_8
# define NEW(type,n) g_try_new (type, n)
# define NEW0(type,n) g_try_new0 (type, n)
#else
# define NEW(type,n) (type*)malloc (sizeof(type)*n)
# define NEW0(type,n) (type*)calloc (n, sizeof(type))
#endif

//survive or exit gracefully when allocation fails
//can implement this now, if so desired
//#define CHECKALLOCATEDFATAL(p) if (p==NULL) e2_utils_memory_error ();
//#define CHECKALLOCATEDWARN(p,more) if (p==NULL) {e2_utils_show_memory_message (); more;}
//#define CHECKALLOCATEDFATALT(p) if (p==NULL) {gdk_threads_enter();e2_utils_memory_error();gdk_threads_leave();}
//#define CHECKALLOCATEDWARNT(p,more) if (p==NULL) {gdk_threads_enter();e2_utils_show_memory_message();gdk_threads_leave(); more;}
#define CHECKALLOCATEDFATAL(p)
#define CHECKALLOCATEDWARN(p,more)
#define CHECKALLOCATEDFATALT(p)
#define CHECKALLOCATEDWARNT(p,more)

//index enumerator for cancellable timers
//CHECKME some other repeating, non-trivial-delay, timers are non-static
enum
{
	FAMPOLL_T,	//polling for reports from file alteration monitor
	DIRTYCHECK_T,	//for polling whether filelists are in need of refresh
	REFRESHBEGIN_T,	//for waiting to start refreshing filelist(s)
	STATUS_T,	//for status-line updates
	CONFIG_T,	//for config-file change checking
	REFRESHWAIT_T,	//for pausing until a prior refresh is completed
	CDWAIT_T,	//for pausing until a prior cd is completed
	ASCROLL_T,	//DnD auto-scroll timer
	MAX_TIMERS
};

#ifdef E2_FAM
typedef enum
{
	E2_MONITOR_DEFAULT,
	E2_MONITOR_FAM,	//unused
	E2_MONITOR_GAMIN
} E2_FAMonitor;
#endif

typedef struct _E2_MainData
{
	GtkWidget *main_window;
	//pair of main boxes that can be surrounded by toolbars
	GtkWidget *hbox_main;
	GtkWidget *vbox_main;
	GtkWidget *outbook; //notebook container for tabbed output-panes
	GtkWidget *status_bar_label2;
	//this is a hbox, at the right of the status bar, for general usage
	// needs to be shown when used
	GtkWidget *status_bar_box3;
	E2_WindowRuntime window;
	E2_PaneRuntime pane1;
	E2_PaneRuntime pane2;
	ViewInfo pane1_view;
	ViewInfo pane2_view;
	E2_ToolbarRuntime toolbar;
	E2_ToolbarRuntime commandbar;
	E2_AliasRuntime aliases;
	E2_OutputRuntime output;	//non-tab-specific data for output pane
	E2_OutputTabRuntime tab;	//tab-specific data for output pane
	GList *tabslist;	//list of E2_OutputTabRuntime's for each tab
	gint tabcount;	//no. of tabs (cached)
	E2_ToolbarData **bars;	//null-terminated array of pointers to toolbar data
	GList *command_lines;	//list of rt data structs of command-lines

#if defined(E2_FAM) && !defined(E2_FAM_KERNEL)
	FAMConnection *fcp;
	FAMEvent *fep;
#endif
#ifdef E2_FAM
	E2_FAMonitor monitor_type;
	gint FAMreq;	//request no used for monitoring config file changes
#endif
	guint timers[MAX_TIMERS];	//glib timer id's
	time_t config_mtime;	//last-logged (seconds) timestamp of config file
#ifndef USE_GTK2_12TIPS
	GtkTooltips *tooltips;
#endif
	GList *plugins;	//list of data structs for all loaded plugins, "non-children"
					//in menu-order (children-submenu-order depends on a list in
					//corresponding parent)
	GHashTable *filetypes;
	GSList *typelist;	//list of string arrays, needed tor cleanup
#ifdef E2_IMAGECACHE
	GHashTable *icons;	//table of E2_Images, for cached icons
#endif
#ifdef E2_RAINBOW
	GHashTable *colors;
	GList *colorchunks;
#endif
	GSList *used_stores;	//for deferred liststore clearing
	GList *taskhistory;
#ifndef E2_FILES_UTF8ONLY
	gboolean utf8_filenames;	//TRUE when filesystem coding is utf-8 or ascii only
#endif
	GdkWindowState mainwindow_state;	//flags indicating changes to main_window
	GtkWidget *context_menu;	//main context-menu when it is popped up
	gint cfgdlg_width;  //config dialog width (cached)
	gint cfgdlg_height; //config dialog height (cached)
	gchar cfgfile_version[20];  //store for config version string eg "0.1.9", used only for upgrades
	gboolean rebuild_enabled;	//set FALSE to block window recreation
#ifdef E2_STATUS_BLOCK
	gboolean status_working;	//set TRUE to block reentrant status-checking etc
#endif
	GHookList hook_pane_focus_changed;
} E2_MainData;

E2_MainData app;
E2_PaneRuntime *curr_pane;
E2_PaneRuntime *other_pane;
ViewInfo *curr_view;
ViewInfo *other_view;
E2_OutputTabRuntime *curr_tab;	//currently-focused member of tabslist

pthread_mutex_t list_mutex;
#define LISTS_LOCK pthread_mutex_lock (&list_mutex);
#define LISTS_UNLOCK pthread_mutex_unlock (&list_mutex);
//CHECKME worth having a separate mutex for this ?
pthread_mutex_t history_mutex;
#define HISTORY_LOCK pthread_mutex_lock (&history_mutex);
#define HISTORY_UNLOCK pthread_mutex_unlock (&history_mutex);

//for testing - define to use gtk's own mutex for BGL
//#define NATIVE_BGL
#ifndef NATIVE_BGL
//local management of gdk mutex, to enable tolerant re-locking by the same thread
#include <pthread.h>
//direct mutex-manipulation
#define gdk_threads_enter e2_main_close_gdklock
#define gdk_threads_leave e2_main_open_gdklock
pthread_mutex_t gdklock;	//BGL replacement
void e2_main_close_gdklock (void);
void e2_main_open_gdklock (void);

	//not locked now and not already locked - this should never happen
	//prevent unlock
#define CLOSEBGL_IF_OPEN \
	gint _lockres; \
	_lockres = pthread_mutex_trylock (&gdklock); \
	printd (DEBUG, "dialog title trylock result %d", _lockres); \
	if (!(_lockres == 0 || _lockres == EBUSY)) \
	{ \
		printd (WARN, "dialog title close BGL failed"); \
		WAIT_FOR_EVENTS_UNLOCKED \
		_lockres = 1; \
	}

#define	OPENBGL_IF_CLOSED \
	if (_lockres == 0) \
		pthread_mutex_unlock (&gdklock);

#else //def NATIVE_BGL
	//WAIT_FOR_EVENTS expects BGL closed
#define CLOSEBGL_IF_OPEN \
	WAIT_FOR_EVENTS_UNLOCKED
#define	OPENBGL_IF_CLOSED
#endif

gboolean e2_main_closedown (gboolean compulsory, gboolean saveconfig, gboolean doexit);
gboolean e2_main_user_shutdown (gpointer from, E2_ActionRuntime *art);
//	__attribute__ ((noreturn));

#endif //ndef __EMELFM2_H__
