<commit_before>/* RTcmix  - Copyright (C) 2004  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <RTcmix.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <ugens.h>      // for die, warn
#include "rtcmix_types.h"
#include <mixerr.h>
#include "prototypes.h"
#include <ug_intro.h>
#include <string.h>
#include <Option.h>

#define WARN_DUPLICATES

typedef struct _func {
   struct _func *next;
   union {
      double (*legacy_return) (float *, int, double *);
      double (*number_return) (const Arg[], int);
      char   *(*string_return) (const Arg[], int);
      Handle (*handle_return) (const Arg[], int);
   } func_ptr;
   RTcmixType return_type;
   const char  *func_label;
   int   legacy;        /* 1 if calling using old signature (w/ p[], pp[]) */
} RTcmixFunction;

struct FunctionEntry {
	FunctionEntry(const char *fname, const char *dsoPath);
	~FunctionEntry();
	char *funcName;
	char *dsoPath;
	struct FunctionEntry *next;
};

/* --------------------------------------------------------------- addfunc -- */
/* Place a function into the table we search when handed a function name
   from the parser.  addfunc is called only from the UG_INTRO* macros.

   This is as cumbersome as it is due to the problem of handling function
   pointers having various return types.  Using the UG_INTRO macros allows
   us to declare the functions in line before passing them to addfunc.

   -JGG, 22 Jan, 2004
*/
void
RTcmix::addfunc(
   const char     	*func_label,            /* name of function exposed to script */
   LegacyFunction 	func_ptr_legacy,
   NumberFunction	func_ptr_number,
   StringFunction 	func_ptr_string,
   HandleFunction 	func_ptr_handle,
   int			    return_type,            /* return type of function */
   int    			legacy)                 /* use old function signature */
{
   RTcmixFunction *cur_node, *this_node;

   /* Create and initialize new list node. */
   this_node = new RTcmixFunction;
   if (this_node == NULL) {
      die("addfunc", "no memory for table of functions");
      return;
   }

   this_node->next = NULL;
   switch (return_type) {
      case DoubleType:
	  	if (legacy)
			this_node->func_ptr.legacy_return = func_ptr_legacy;
		else
			this_node->func_ptr.number_return = func_ptr_number;
         break;
      case StringType:
         this_node->func_ptr.string_return = func_ptr_string;
         break;
      case HandleType:
         this_node->func_ptr.handle_return = func_ptr_handle;
         break;
      default:
         die("addfunc", "invalid function return type");
         return;
   }
   this_node->return_type = (RTcmixType) return_type;
   this_node->func_label = func_label;
   this_node->legacy = legacy;

    bool autoload = Option::autoLoad();
   /* Place new node at tail of list.  Warn if this function name is already
      in list.
   */
   if (_func_list == NULL) {
      _func_list = this_node;
      return;
   }
   cur_node = _func_list;
   for ( ; cur_node->next; cur_node = cur_node->next) {
#ifdef WARN_DUPLICATES
      if (strcmp(cur_node->func_label, this_node->func_label) == 0) {
         if (!autoload)
             rtcmix_warn("addfunc", "Function '%s' already introduced",
                  this_node->func_label);
          delete this_node;
         return;
      }
#endif
   }
//    RTPrintf("addfunc: Function '%s' introduced\n", this_node->func_label);
   cur_node->next = this_node;
}

/* ----------------------------------------------------------- freefuncs -- */
void
RTcmix::freefuncs()
{
	for (RTcmixFunction *cur_node = _func_list; cur_node; ) {
		RTcmixFunction *next = cur_node->next;
		delete cur_node;
		cur_node = next;
	}
	_func_list = NULL;

	// DAS added 01/2014

	for (FunctionEntry *entry = _functionRegistry; entry; ) {
		FunctionEntry *next = entry->next;
		delete entry;
		entry = next;
	}
	_functionRegistry = NULL;
}

/* ------------------------------------------------------------- findfunc -- */
static RTcmixFunction *
findfunc(RTcmixFunction *func_list, const char *func_label)
{
   RTcmixFunction *cur_node;

   for (cur_node = func_list; cur_node; cur_node = cur_node->next) {
      if (strcmp(cur_node->func_label, func_label) == 0) {
         return cur_node;
         break;
      }
   }
   return NULL;
}

/* ------------------------------------------------------------ _printargs -- */
static void
_printargs(const char *funcname, const Arg arglist[], const int nargs)
{
   int i;
   Arg arg;

   if (Option::print() >= MMP_PRINTALL) {
      RTPrintf("============================\n");
      RTPrintfCat("%s:  ", funcname);
      for (i = 0; i < nargs; i++) {
         arglist[i].printInline(stdout);
      }
      RTPrintf("\n");
   }
}

/* ------------------------------------------------------------- checkfunc -- */
int
RTcmix::checkfunc(const char *funcname, const Arg arglist[], const int nargs,
		          Arg *retval)
{
   RTcmixFunction *func;

   func = ::findfunc(_func_list, funcname);

   // If we did not find it, try loading it from our list of registered DSOs.
   if (func == NULL) {
      if (findAndLoadFunction(funcname) == 0) {
         func = ::findfunc(_func_list, funcname);
		  if (func == NULL) {
			   mixerr = MX_FNAME;
               return -1;
		  }
      }
      else {
		  mixerr = MX_FNAME;
		  return -1;
	  }
   }

   /* function found, so call it */

   ::_printargs(funcname, arglist, nargs);

   int status = 0;

   switch (func->return_type) {
   case DoubleType:
      if (func->legacy) {
         /* for old (float p[], int nargs, double pp[]) signature */
         #include <maxdispargs.h>
         float p[MAXDISPARGS];
         double pp[MAXDISPARGS];
         for (int i = 0; i < nargs; i++) {
			const Arg &theArg = arglist[i];
            p[i] = (float) theArg;
			switch (theArg.type()) {
            case DoubleType:
               pp[i] = (double) theArg;
			   break;
            case StringType:
               pp[i] = STRING_TO_DOUBLE(theArg);
			   break;
            default:
               return die(NULL, "%s: arguments must be numbers or strings.", funcname);
            }
         }
         /* some functions rely on zero contents of args > nargs */
         for (int i = nargs; i < MAXDISPARGS; i++) {
            p[i] = 0.0;
            pp[i] = 0.0;
         }
         *retval = (double) (*(func->func_ptr.legacy_return))
                                                      (p, nargs, pp);
      }
      else
         *retval = (double) (*(func->func_ptr.number_return))
                                                      (arglist, nargs);
      break;
   case HandleType:
	  {
      Handle retHandle = (Handle) (*(func->func_ptr.handle_return))
                                                      (arglist, nargs);
	  if (retHandle == NULL) {
		  status = -1;
		  mixerr = MX_FAIL;
	  }
	  *retval = retHandle;
	  }
      break;
   case StringType:
	  {
      const char *retString = (const char *) (*(func->func_ptr.string_return))
                                                      (arglist, nargs);
	  if (retString == NULL) {
		  status = -1;
		  mixerr = MX_FAIL;
	  }
	  *retval = retString;
	  }
      break;
   default:
	  die(NULL, "%s: unhandled return type: %d", funcname, (int)func->return_type);
	  status = -1;
	  mixerr = MX_FAIL;
      break;
   }

   return status;
}

// Code for function/DSO registry, which allows RTcmix to auto-load a DSO
// for a given function.

FunctionEntry::FunctionEntry(const char *fname, const char *dso_path)
	: funcName(strdup(fname)), dsoPath(strdup(dso_path)), next(NULL)
{
}

FunctionEntry::~FunctionEntry()
{
	free(dsoPath);
	free(funcName);
}

static FunctionEntry *
findFunctionEntry(FunctionEntry *entry, const char *funcname)
{
	while (entry != NULL) {
		if (!strcmp(entry->funcName, funcname))
			return entry;
		entry = entry->next;
	}
	return NULL;
}

static const char *
getDSOPath(FunctionEntry *entry, const char *funcname)
{
	FunctionEntry * fentry = findFunctionEntry(entry, funcname);
	if (fentry != NULL)
        return fentry->dsoPath;
	return NULL;
}

extern "C" double m_load(float *, int, double *);	// loader.c

/* --------------------------------------------------- findAndLoadFunction -- */

// Called by RTcmix::checkfunc() to allow auto-loading of DSOs.

int
RTcmix::findAndLoadFunction(const char *funcname)
{
	const char *path;
	int status = -1;
	if ((path = ::getDSOPath(_functionRegistry, funcname)) != NULL) {
		char fullDSOPath[128];
		float p[1];
		double pp[1];
		sprintf(fullDSOPath, "%s.so", path);
		p[0] = 0;
		pp[0] = STRING_TO_DOUBLE(fullDSOPath);
//        RTPrintf("findAndLoadFunction: calling load() on '%s' for function '%s'\n", fullDSOPath, funcname);
		if (m_load(p, 1, pp) == 1)
			status = 0;
		else
			status = -1;
	}
	return status;
}

/* ------------------------------------------------------ registerFunction -- */

// This is called by each DSO's registerMe() function to register a given
// Minc command name (function name) with a particular DSO name.  When
// RTcmix::checkfunc() fails to find a functions, it calls findAndLoadFunction()
// to search the function/DSO database for a matching DSO.

int
RTcmix::registerFunction(const char *funcName, const char *dsoPath)
{
	const char *path;
	if ((path = ::getDSOPath(_functionRegistry, funcName)) == NULL) {
		FunctionEntry *newEntry = new FunctionEntry(funcName, dsoPath);
		newEntry->next = _functionRegistry;
		_functionRegistry = newEntry;
		RTPrintf("RTcmix::registerFunction: registered function '%s' for dso '%s'\n",
				funcName, dsoPath);
		return 0;
	}
	else {
		rtcmix_warn("RTcmix::registerFunction",
			  "'%s' already registered for DSO '%s'", funcName, path);
		return -1;
	}
}

#include <dirent.h>
#include "DynamicLib.h"

/* ------------------------------------------------------ registerDSOs -- */
// This is called at initialization time to scan a supplied semicolon-separated
// list of directories for DSOs (files which begin with "lib").  When found,
// each is searched for a "registerSelf()" function, which is called.

typedef int (*RegisterFunction)();

int
RTcmix::registerDSOs(const char *pathList)
{
	const char *list = pathList;
	while (list != NULL) {
		char path[1024];
		long itemLen;
		const char *nextItem = strchr(list, ':');
		if (nextItem != NULL) {
			itemLen = nextItem - list;
			++nextItem;		// skip semicolon
		}
		else {
			itemLen = strlen(list);
		}
		strncpy(path, list, itemLen);
		path[itemLen] = '\0';

		DIR *dsoDir = opendir(path);
		if (dsoDir != NULL) {
			struct dirent *entry;
			while ((entry = readdir(dsoDir)) != NULL) {
				if (strncmp(entry->d_name, "lib", 3) == 0) {
					char fullPath[1024];
					sprintf(fullPath, "%s/%s", path, entry->d_name);
					DynamicLib dso;
					if (dso.load(fullPath) == 0) {
						RegisterFunction registerMe = NULL;
//						RTPrintf("opened DSO '%s'\n", fullPath);
						if (dso.loadFunction(&registerMe, "registerSelf") == 0)
						{
//							RTPrintf("\tcalling register function.\n");
							(*registerMe)();
						}
						dso.unload();
					}
				}
			}
			closedir(dsoDir);
		}
		list = nextItem;
	}
	return 0;
}

// Wrappers for UG_INTRO() use.

extern "C" {
void addfunc(
   const char     	*func_label,            /* name of function exposed to script */
   LegacyFunction 	func_ptr_legacy,
   NumberFunction	func_ptr_number,
   StringFunction 	func_ptr_string,
   HandleFunction 	func_ptr_handle,
   RTcmixType		return_type,            /* return type of function */
   int    			legacy)                 /* use old function signature */
{
	RTcmix::addfunc(func_label, func_ptr_legacy, func_ptr_number,
				    func_ptr_string, func_ptr_handle, return_type, legacy);
}
};

void
addLegacyfunc(const char *label, double (*func_ptr)(float *, int, double *))
{
	RTcmix::addfunc(label, func_ptr, NULL, NULL, NULL, DoubleType, 1);
}

int
registerFunction(const char *funcName, const char *dsoPath)
{
	return RTcmix::registerFunction(funcName, dsoPath);
}
<commit_msg>Changed some logging.<commit_after>/* RTcmix  - Copyright (C) 2004  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <RTcmix.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <ugens.h>      // for die, warn
#include "rtcmix_types.h"
#include <mixerr.h>
#include "prototypes.h"
#include <ug_intro.h>
#include <string.h>
#include <Option.h>

#define WARN_DUPLICATES

typedef struct _func {
   struct _func *next;
   union {
      double (*legacy_return) (float *, int, double *);
      double (*number_return) (const Arg[], int);
      char   *(*string_return) (const Arg[], int);
      Handle (*handle_return) (const Arg[], int);
   } func_ptr;
   RTcmixType return_type;
   const char  *func_label;
   int   legacy;        /* 1 if calling using old signature (w/ p[], pp[]) */
} RTcmixFunction;

struct FunctionEntry {
	FunctionEntry(const char *fname, const char *dsoPath);
	~FunctionEntry();
	char *funcName;
	char *dsoPath;
	struct FunctionEntry *next;
};

/* --------------------------------------------------------------- addfunc -- */
/* Place a function into the table we search when handed a function name
   from the parser.  addfunc is called only from the UG_INTRO* macros.

   This is as cumbersome as it is due to the problem of handling function
   pointers having various return types.  Using the UG_INTRO macros allows
   us to declare the functions in line before passing them to addfunc.

   -JGG, 22 Jan, 2004
*/
void
RTcmix::addfunc(
   const char     	*func_label,            /* name of function exposed to script */
   LegacyFunction 	func_ptr_legacy,
   NumberFunction	func_ptr_number,
   StringFunction 	func_ptr_string,
   HandleFunction 	func_ptr_handle,
   int			    return_type,            /* return type of function */
   int    			legacy)                 /* use old function signature */
{
   RTcmixFunction *cur_node, *this_node;

   /* Create and initialize new list node. */
   this_node = new RTcmixFunction;
   if (this_node == NULL) {
      die("addfunc", "no memory for table of functions");
      return;
   }

   this_node->next = NULL;
   switch (return_type) {
      case DoubleType:
	  	if (legacy)
			this_node->func_ptr.legacy_return = func_ptr_legacy;
		else
			this_node->func_ptr.number_return = func_ptr_number;
         break;
      case StringType:
         this_node->func_ptr.string_return = func_ptr_string;
         break;
      case HandleType:
         this_node->func_ptr.handle_return = func_ptr_handle;
         break;
      default:
         die("addfunc", "invalid function return type");
         return;
   }
   this_node->return_type = (RTcmixType) return_type;
   this_node->func_label = func_label;
   this_node->legacy = legacy;

    bool autoload = Option::autoLoad();
   /* Place new node at tail of list.  Warn if this function name is already
      in list.
   */
   if (_func_list == NULL) {
      _func_list = this_node;
      return;
   }
   cur_node = _func_list;
   for ( ; cur_node->next; cur_node = cur_node->next) {
#ifdef WARN_DUPLICATES
      if (strcmp(cur_node->func_label, this_node->func_label) == 0) {
         if (!autoload)
             rtcmix_warn("addfunc", "Function '%s' already introduced",
                  this_node->func_label);
          delete this_node;
         return;
      }
#endif
   }
//   RTPrintf("addfunc: Function '%s' introduced at %p\n", this_node->func_label, this_node->func_ptr.legacy_return);
   cur_node->next = this_node;
}

/* ----------------------------------------------------------- freefuncs -- */
void
RTcmix::freefuncs()
{
	for (RTcmixFunction *cur_node = _func_list; cur_node; ) {
		RTcmixFunction *next = cur_node->next;
		delete cur_node;
		cur_node = next;
	}
	_func_list = NULL;

	// DAS added 01/2014

	for (FunctionEntry *entry = _functionRegistry; entry; ) {
		FunctionEntry *next = entry->next;
		delete entry;
		entry = next;
	}
	_functionRegistry = NULL;
}

/* ------------------------------------------------------------- findfunc -- */
static RTcmixFunction *
findfunc(RTcmixFunction *func_list, const char *func_label)
{
   RTcmixFunction *cur_node;

   for (cur_node = func_list; cur_node; cur_node = cur_node->next) {
      if (strcmp(cur_node->func_label, func_label) == 0) {
         return cur_node;
         break;
      }
   }
   return NULL;
}

/* ------------------------------------------------------------ _printargs -- */
static void
_printargs(const char *funcname, const Arg arglist[], const int nargs)
{
   int i;
   Arg arg;

   if (Option::print() >= MMP_PRINTALL) {
      RTPrintf("============================\n");
      RTPrintfCat("%s:  ", funcname);
      for (i = 0; i < nargs; i++) {
         arglist[i].printInline(stdout);
      }
      RTPrintf("\n");
   }
}

/* ------------------------------------------------------------- checkfunc -- */
int
RTcmix::checkfunc(const char *funcname, const Arg arglist[], const int nargs,
		          Arg *retval)
{
   RTcmixFunction *func;

   func = ::findfunc(_func_list, funcname);

   // If we did not find it, try loading it from our list of registered DSOs.
   if (func == NULL) {
      if (findAndLoadFunction(funcname) == 0) {
         func = ::findfunc(_func_list, funcname);
		  if (func == NULL) {
			   mixerr = MX_FNAME;
               return -1;
		  }
      }
      else {
		  mixerr = MX_FNAME;
		  return -1;
	  }
   }

   /* function found, so call it */

   ::_printargs(funcname, arglist, nargs);

   int status = 0;

   switch (func->return_type) {
   case DoubleType:
      if (func->legacy) {
         /* for old (float p[], int nargs, double pp[]) signature */
         #include <maxdispargs.h>
         float p[MAXDISPARGS];
         double pp[MAXDISPARGS];
         for (int i = 0; i < nargs; i++) {
			const Arg &theArg = arglist[i];
            p[i] = (float) theArg;
			switch (theArg.type()) {
            case DoubleType:
               pp[i] = (double) theArg;
			   break;
            case StringType:
               pp[i] = STRING_TO_DOUBLE(theArg);
			   break;
            default:
               return die(NULL, "%s: arguments must be numbers or strings.", funcname);
            }
         }
         /* some functions rely on zero contents of args > nargs */
         for (int i = nargs; i < MAXDISPARGS; i++) {
            p[i] = 0.0;
            pp[i] = 0.0;
         }
         *retval = (double) (*(func->func_ptr.legacy_return))
                                                      (p, nargs, pp);
      }
      else
         *retval = (double) (*(func->func_ptr.number_return))
                                                      (arglist, nargs);
      break;
   case HandleType:
	  {
      Handle retHandle = (Handle) (*(func->func_ptr.handle_return))
                                                      (arglist, nargs);
	  if (retHandle == NULL) {
		  status = -1;
		  mixerr = MX_FAIL;
	  }
	  *retval = retHandle;
	  }
      break;
   case StringType:
	  {
      const char *retString = (const char *) (*(func->func_ptr.string_return))
                                                      (arglist, nargs);
	  if (retString == NULL) {
		  status = -1;
		  mixerr = MX_FAIL;
	  }
	  *retval = retString;
	  }
      break;
   default:
	  die(NULL, "%s: unhandled return type: %d", funcname, (int)func->return_type);
	  status = -1;
	  mixerr = MX_FAIL;
      break;
   }

   return status;
}

// Code for function/DSO registry, which allows RTcmix to auto-load a DSO
// for a given function.

FunctionEntry::FunctionEntry(const char *fname, const char *dso_path)
	: funcName(strdup(fname)), dsoPath(strdup(dso_path)), next(NULL)
{
}

FunctionEntry::~FunctionEntry()
{
	free(dsoPath);
	free(funcName);
}

static FunctionEntry *
findFunctionEntry(FunctionEntry *entry, const char *funcname)
{
	while (entry != NULL) {
		if (!strcmp(entry->funcName, funcname))
			return entry;
		entry = entry->next;
	}
	return NULL;
}

static const char *
getDSOPath(FunctionEntry *entry, const char *funcname)
{
	FunctionEntry * fentry = findFunctionEntry(entry, funcname);
	if (fentry != NULL)
        return fentry->dsoPath;
	return NULL;
}

extern "C" double m_load(float *, int, double *);	// loader.c

/* --------------------------------------------------- findAndLoadFunction -- */

// Called by RTcmix::checkfunc() to allow auto-loading of DSOs.

int
RTcmix::findAndLoadFunction(const char *funcname)
{
	const char *path;
	int status = -1;
	if ((path = ::getDSOPath(_functionRegistry, funcname)) != NULL) {
		char fullDSOPath[128];
		float p[1];
		double pp[1];
		sprintf(fullDSOPath, "%s.so", path);
		p[0] = 0;
		pp[0] = STRING_TO_DOUBLE(fullDSOPath);
//        RTPrintf("findAndLoadFunction: calling load() on '%s' for function '%s'\n", fullDSOPath, funcname);
		if (m_load(p, 1, pp) == 1)
			status = 0;
		else
			status = -1;
	}
	return status;
}

/* ------------------------------------------------------ registerFunction -- */

// This is called by each DSO's registerMe() function to register a given
// Minc command name (function name) with a particular DSO name.  When
// RTcmix::checkfunc() fails to find a functions, it calls findAndLoadFunction()
// to search the function/DSO database for a matching DSO.

int
RTcmix::registerFunction(const char *funcName, const char *dsoPath)
{
	const char *path;
	if ((path = ::getDSOPath(_functionRegistry, funcName)) == NULL) {
		FunctionEntry *newEntry = new FunctionEntry(funcName, dsoPath);
		newEntry->next = _functionRegistry;
		_functionRegistry = newEntry;
		RTPrintf("RTcmix::registerFunction: registered function '%s' for dso '%s'\n",
				funcName, dsoPath);
		return 0;
	}
	else {
		rtcmix_warn("RTcmix::registerFunction",
			  "'%s' already registered for DSO '%s'", funcName, path);
		return -1;
	}
}

#include <dirent.h>
#include "DynamicLib.h"

/* ------------------------------------------------------ registerDSOs -- */
// This is called at initialization time to scan a supplied semicolon-separated
// list of directories for DSOs (files which begin with "lib").  When found,
// each is searched for a "registerSelf()" function, which is called.

typedef int (*RegisterFunction)();

int
RTcmix::registerDSOs(const char *pathList)
{
	const char *list = pathList;
	while (list != NULL) {
		char path[1024];
		long itemLen;
		const char *nextItem = strchr(list, ':');
		if (nextItem != NULL) {
			itemLen = nextItem - list;
			++nextItem;		// skip semicolon
		}
		else {
			itemLen = strlen(list);
		}
		strncpy(path, list, itemLen);
		path[itemLen] = '\0';

		DIR *dsoDir = opendir(path);
		if (dsoDir != NULL) {
			struct dirent *entry;
			while ((entry = readdir(dsoDir)) != NULL) {
				if (strncmp(entry->d_name, "lib", 3) == 0) {
					char fullPath[1024];
					sprintf(fullPath, "%s/%s", path, entry->d_name);
					DynamicLib dso;
					if (dso.load(fullPath) == 0) {
						RegisterFunction registerMe = NULL;
//						RTPrintf("opened DSO '%s'\n", fullPath);
						if (dso.loadFunction(&registerMe, "registerSelf") == 0)
						{
//							RTPrintf("\tcalling register function.\n");
							(*registerMe)();
						}
						dso.unload();
					}
				}
			}
			closedir(dsoDir);
		}
		list = nextItem;
	}
	return 0;
}

// Wrappers for UG_INTRO() use.

extern "C" {
void addfunc(
   const char     	*func_label,            /* name of function exposed to script */
   LegacyFunction 	func_ptr_legacy,
   NumberFunction	func_ptr_number,
   StringFunction 	func_ptr_string,
   HandleFunction 	func_ptr_handle,
   RTcmixType		return_type,            /* return type of function */
   int    			legacy)                 /* use old function signature */
{
	RTcmix::addfunc(func_label, func_ptr_legacy, func_ptr_number,
				    func_ptr_string, func_ptr_handle, return_type, legacy);
}
};

void
addLegacyfunc(const char *label, double (*func_ptr)(float *, int, double *))
{
	RTcmix::addfunc(label, func_ptr, NULL, NULL, NULL, DoubleType, 1);
}

int
registerFunction(const char *funcName, const char *dsoPath)
{
	return RTcmix::registerFunction(funcName, dsoPath);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <QApplication>
#include <QTimer>

#include <boost/program_options.hpp>

#include <OgreMaterialManager.h>
#include <OgreGpuProgramManager.h>
#include <OgreHighLevelGpuProgramManager.h>
#include <std_srvs/Empty.h>

#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
// Apparently OSX #defines 'check' to be an empty string somewhere.
// That was fun to figure out.
#undef check
#endif

#include <ros/ros.h>

#include "rviz/selection/selection_manager.h"
#include "rviz/env_config.h"
#include "rviz/ogre_helpers/ogre_logging.h"
#include "rviz/visualization_frame.h"
#include "rviz/visualization_manager.h"
#include "rviz/wait_for_master_dialog.h"
#include "rviz/ogre_helpers/render_system.h"

#include "rviz/visualizer_app.h"

#define CATCH_EXCEPTIONS 0

namespace po = boost::program_options;

namespace rviz
{

bool reloadShaders(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
  ROS_INFO("Reloading materials.");
  {
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::MaterialManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  }
  ROS_INFO("Reloading high-level gpu shaders.");
  {
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::HighLevelGpuProgramManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  }
  ROS_INFO("Reloading gpu shaders.");
  {
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::GpuProgramManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  }
  return true;
}

VisualizerApp::VisualizerApp()
  : continue_timer_( 0 )
  , frame_( 0 )
{
}

bool VisualizerApp::init( int argc, char** argv )
{
  ROS_INFO( "rviz version %s", get_version().c_str() );
  ROS_INFO( "compiled against OGRE version %d.%d.%d%s (%s)",
            OGRE_VERSION_MAJOR, OGRE_VERSION_MINOR, OGRE_VERSION_PATCH,
            OGRE_VERSION_SUFFIX, OGRE_VERSION_NAME );

#ifdef Q_OS_MAC
  ProcessSerialNumber PSN;
  GetCurrentProcess(&PSN);
  TransformProcessType(&PSN,kProcessTransformToForegroundApplication);
  SetFrontProcess(&PSN);
#endif

#if CATCH_EXCEPTIONS
  try
  {
#endif
    ros::init( argc, argv, "rviz", ros::init_options::AnonymousName );

    startContinueChecker();

    po::options_description options;
    options.add_options()
      ("help,h", "Produce this help message")
      ("splash-screen,s", po::value<std::string>(), "A custom splash-screen image to display")
      ("help-file", po::value<std::string>(), "A custom html file to show as the help screen")
      ("display-config,d", po::value<std::string>(), "A display config file (.rviz) to load")
      ("fixed-frame,f", po::value<std::string>(), "Set the fixed frame")
      ("ogre-log,l", "Enable the Ogre.log file (output in cwd) and console output.")
      ("in-mc-wrapper", "Signal that this is running inside a master-chooser wrapper")
      ("opengl", po::value<int>(), "Force OpenGL version (use '--opengl 210' for OpenGL 2.1 compatibility mode)")
      ("no-stereo", "Disable the use of stereo rendering.")
      ("verbose,v", "Enable debug visualizations");
    po::variables_map vm;
    std::string display_config, fixed_frame, splash_path, help_path;
    bool enable_ogre_log = false;
    bool in_mc_wrapper = false;
    bool verbose = false;
    int force_gl_version = 0;
	bool disable_stereo = false;
    try
    {
      po::store( po::parse_command_line( argc, argv, options ), vm );
      po::notify( vm );

      if( vm.count( "help" ))
      {
        std::cout << "rviz command line options:\n" << options;
        return false;
      }

      if( vm.count( "in-mc-wrapper" ))
      {
        in_mc_wrapper = true;
      }

      if (vm.count("display-config"))
      {
        display_config = vm["display-config"].as<std::string>();
        if( display_config.substr( display_config.size() - 4, 4 ) == ".vcg" )
        {
          std::cerr << "ERROR: the config file '" << display_config << "' is a .vcg file, which is the old rviz config format." << std::endl;
          std::cerr << "       New config files have a .rviz extension and use YAML formatting.  The format changed" << std::endl;
          std::cerr << "       between Fuerte and Groovy.  There is not (yet) an automated conversion program." << std::endl;
          return false;
        }
      }

      if (vm.count("splash-screen"))
      {
        splash_path = vm["splash-screen"].as<std::string>();
      }

      if (vm.count("help-file"))
      {
        help_path = vm["help-file"].as<std::string>();
      }

      if (vm.count("fixed-frame"))
      {
        fixed_frame = vm["fixed-frame"].as<std::string>();
      }

      if (vm.count("ogre-log"))
      {
        enable_ogre_log = true;
      }

      if (vm.count("no-stereo"))
      {
        disable_stereo = true;
      }

      if (vm.count("opengl"))
      {
        //std::cout << vm["opengl"].as<std::string>() << std::endl;
        force_gl_version = vm["opengl"].as<int>();
      }

      if (vm.count("verbose"))
      {
        verbose = true;
      }
    }
    catch (std::exception& e)
    {
      ROS_ERROR("Error parsing command line: %s", e.what());
      return false;
    }

    if( !ros::master::check() )
    {
      WaitForMasterDialog* dialog = new WaitForMasterDialog;
      if( dialog->exec() != QDialog::Accepted )
      {
        return false;
      }
    }

    nh_.reset( new ros::NodeHandle );

    if( enable_ogre_log )
    {
      OgreLogging::useRosLog();
    }

    if ( force_gl_version )
    {
      RenderSystem::forceGlVersion( force_gl_version );
    }

    if ( disable_stereo )
    {
      RenderSystem::forceNoStereo();
    }

    frame_ = new VisualizationFrame;
    if( help_path != "" )
    {
      frame_->setHelpPath( QString::fromStdString( help_path ));
    }
    frame_->setShowChooseNewMaster( in_mc_wrapper );
    if( splash_path != "" )
    {
      frame_->setSplashPath( QString::fromStdString( splash_path ));
    }
    frame_->initialize( QString::fromStdString( display_config ));
    if( !fixed_frame.empty() )
    {
      frame_->getManager()->setFixedFrame( QString::fromStdString( fixed_frame ));
    }

    frame_->getManager()->getSelectionManager()->setDebugMode( verbose );

    frame_->show();

    ros::NodeHandle private_nh("~");
    reload_shaders_service_ = private_nh.advertiseService("reload_shaders", reloadShaders);

#if CATCH_EXCEPTIONS
  }
  catch (std::exception& e)
  {
    ROS_ERROR("Caught exception while loading: %s", e.what());
    return false;
  }
#endif
  return true;
}

VisualizerApp::~VisualizerApp()
{
  delete continue_timer_;
  delete frame_;
}

void VisualizerApp::startContinueChecker()
{
  continue_timer_ = new QTimer( this );
  connect( continue_timer_, SIGNAL( timeout() ), this, SLOT( checkContinue() ));
  continue_timer_->start( 100 );
}

void VisualizerApp::checkContinue()
{
  if( !ros::ok() )
  {
    if( frame_ )
    {
      // Make sure the window doesn't ask if we want to save first.
      frame_->setWindowModified( false );
    }
    QApplication::closeAllWindows();
  }
}

} // namespace rviz
<commit_msg>add option to start rviz with the ROS logger level set to Debug<commit_after>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <QApplication>
#include <QTimer>

#include <boost/program_options.hpp>

#include <OgreMaterialManager.h>
#include <OgreGpuProgramManager.h>
#include <OgreHighLevelGpuProgramManager.h>
#include <std_srvs/Empty.h>

#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
// Apparently OSX #defines 'check' to be an empty string somewhere.
// That was fun to figure out.
#undef check
#endif

#include <ros/console.h>
#include <ros/ros.h>

#include "rviz/selection/selection_manager.h"
#include "rviz/env_config.h"
#include "rviz/ogre_helpers/ogre_logging.h"
#include "rviz/visualization_frame.h"
#include "rviz/visualization_manager.h"
#include "rviz/wait_for_master_dialog.h"
#include "rviz/ogre_helpers/render_system.h"

#include "rviz/visualizer_app.h"

#define CATCH_EXCEPTIONS 0

namespace po = boost::program_options;

namespace rviz
{

bool reloadShaders(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
  ROS_INFO("Reloading materials.");
  {
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::MaterialManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  }
  ROS_INFO("Reloading high-level gpu shaders.");
  {
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::HighLevelGpuProgramManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  }
  ROS_INFO("Reloading gpu shaders.");
  {
  Ogre::ResourceManager::ResourceMapIterator it = Ogre::GpuProgramManager::getSingleton().getResourceIterator();
  while (it.hasMoreElements())
  {
    Ogre::ResourcePtr resource = it.getNext();
    resource->reload();
  }
  }
  return true;
}

VisualizerApp::VisualizerApp()
  : continue_timer_( 0 )
  , frame_( 0 )
{
}

bool VisualizerApp::init( int argc, char** argv )
{
  ROS_INFO( "rviz version %s", get_version().c_str() );
  ROS_INFO( "compiled against OGRE version %d.%d.%d%s (%s)",
            OGRE_VERSION_MAJOR, OGRE_VERSION_MINOR, OGRE_VERSION_PATCH,
            OGRE_VERSION_SUFFIX, OGRE_VERSION_NAME );

#ifdef Q_OS_MAC
  ProcessSerialNumber PSN;
  GetCurrentProcess(&PSN);
  TransformProcessType(&PSN,kProcessTransformToForegroundApplication);
  SetFrontProcess(&PSN);
#endif

#if CATCH_EXCEPTIONS
  try
  {
#endif
    ros::init( argc, argv, "rviz", ros::init_options::AnonymousName );

    startContinueChecker();

    po::options_description options;
    options.add_options()
      ("help,h", "Produce this help message")
      ("splash-screen,s", po::value<std::string>(), "A custom splash-screen image to display")
      ("help-file", po::value<std::string>(), "A custom html file to show as the help screen")
      ("display-config,d", po::value<std::string>(), "A display config file (.rviz) to load")
      ("fixed-frame,f", po::value<std::string>(), "Set the fixed frame")
      ("ogre-log,l", "Enable the Ogre.log file (output in cwd) and console output.")
      ("in-mc-wrapper", "Signal that this is running inside a master-chooser wrapper")
      ("opengl", po::value<int>(), "Force OpenGL version (use '--opengl 210' for OpenGL 2.1 compatibility mode)")
      ("no-stereo", "Disable the use of stereo rendering.")
      ("verbose,v", "Enable debug visualizations")
      ("log-level-debug", "Sets the ROS logger level to debug.");
    po::variables_map vm;
    std::string display_config, fixed_frame, splash_path, help_path;
    bool enable_ogre_log = false;
    bool in_mc_wrapper = false;
    bool verbose = false;
    int force_gl_version = 0;
    bool disable_stereo = false;
    try
    {
      po::store( po::parse_command_line( argc, argv, options ), vm );
      po::notify( vm );

      if( vm.count( "help" ))
      {
        std::cout << "rviz command line options:\n" << options;
        return false;
      }

      if( vm.count( "in-mc-wrapper" ))
      {
        in_mc_wrapper = true;
      }

      if (vm.count("display-config"))
      {
        display_config = vm["display-config"].as<std::string>();
        if( display_config.substr( display_config.size() - 4, 4 ) == ".vcg" )
        {
          std::cerr << "ERROR: the config file '" << display_config << "' is a .vcg file, which is the old rviz config format." << std::endl;
          std::cerr << "       New config files have a .rviz extension and use YAML formatting.  The format changed" << std::endl;
          std::cerr << "       between Fuerte and Groovy.  There is not (yet) an automated conversion program." << std::endl;
          return false;
        }
      }

      if (vm.count("splash-screen"))
      {
        splash_path = vm["splash-screen"].as<std::string>();
      }

      if (vm.count("help-file"))
      {
        help_path = vm["help-file"].as<std::string>();
      }

      if (vm.count("fixed-frame"))
      {
        fixed_frame = vm["fixed-frame"].as<std::string>();
      }

      if (vm.count("ogre-log"))
      {
        enable_ogre_log = true;
      }

      if (vm.count("no-stereo"))
      {
        disable_stereo = true;
      }

      if (vm.count("opengl"))
      {
        //std::cout << vm["opengl"].as<std::string>() << std::endl;
        force_gl_version = vm["opengl"].as<int>();
      }

      if (vm.count("verbose"))
      {
        verbose = true;
      }

      if (vm.count("log-level-debug"))
      {
        if( ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Debug) )
        {
          ros::console::notifyLoggerLevelsChanged();
        }
      }
    }
    catch (std::exception& e)
    {
      ROS_ERROR("Error parsing command line: %s", e.what());
      return false;
    }

    if( !ros::master::check() )
    {
      WaitForMasterDialog* dialog = new WaitForMasterDialog;
      if( dialog->exec() != QDialog::Accepted )
      {
        return false;
      }
    }

    nh_.reset( new ros::NodeHandle );

    if( enable_ogre_log )
    {
      OgreLogging::useRosLog();
    }

    if ( force_gl_version )
    {
      RenderSystem::forceGlVersion( force_gl_version );
    }

    if ( disable_stereo )
    {
      RenderSystem::forceNoStereo();
    }

    frame_ = new VisualizationFrame;
    if( help_path != "" )
    {
      frame_->setHelpPath( QString::fromStdString( help_path ));
    }
    frame_->setShowChooseNewMaster( in_mc_wrapper );
    if( splash_path != "" )
    {
      frame_->setSplashPath( QString::fromStdString( splash_path ));
    }
    frame_->initialize( QString::fromStdString( display_config ));
    if( !fixed_frame.empty() )
    {
      frame_->getManager()->setFixedFrame( QString::fromStdString( fixed_frame ));
    }

    frame_->getManager()->getSelectionManager()->setDebugMode( verbose );

    frame_->show();

    ros::NodeHandle private_nh("~");
    reload_shaders_service_ = private_nh.advertiseService("reload_shaders", reloadShaders);

#if CATCH_EXCEPTIONS
  }
  catch (std::exception& e)
  {
    ROS_ERROR("Caught exception while loading: %s", e.what());
    return false;
  }
#endif
  return true;
}

VisualizerApp::~VisualizerApp()
{
  delete continue_timer_;
  delete frame_;
}

void VisualizerApp::startContinueChecker()
{
  continue_timer_ = new QTimer( this );
  connect( continue_timer_, SIGNAL( timeout() ), this, SLOT( checkContinue() ));
  continue_timer_->start( 100 );
}

void VisualizerApp::checkContinue()
{
  if( !ros::ok() )
  {
    if( frame_ )
    {
      // Make sure the window doesn't ask if we want to save first.
      frame_->setWindowModified( false );
    }
    QApplication::closeAllWindows();
  }
}

} // namespace rviz
<|endoftext|>


<commit_before>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "devicekeys.h"
#include <QGuiApplication>
#include <QDebug>
#include <QEvent>
#include <QKeyEvent>
#include <QTimer>
#include <QWindow>

DeviceKeys::DeviceKeys(QObject *parent) :
  QObject(parent),
  m_repeating(true),
  m_active(false),
  m_timer(new QTimer(this)),
  m_event(0),
  m_key(0) {

  m_timer->setInterval(100);
  m_timer->setSingleShot(false);

  QObject::connect(m_timer, SIGNAL(timeout()), this, SLOT(repeatEventsIfNeeded()));

  QGuiApplication::instance()->installEventFilter(this);
}

DeviceKeys::~DeviceKeys() {

}

bool DeviceKeys::eventFilter(QObject *obj, QEvent *event) {
  if (!m_active) {
    return QObject::eventFilter(obj, event);
  }

  QWindow *win = dynamic_cast<QWindow *>(obj);
  if (!win || !QGuiApplication::allWindows().contains(win)) {
    return QObject::eventFilter(obj, event);
  }

  int ev = event->type();
  if (ev == QEvent::KeyPress || ev == QEvent::KeyRelease) {
    QKeyEvent *e = dynamic_cast<QKeyEvent *>(event);
    int key = e->key();

    if (key == Qt::Key_VolumeUp || key == Qt::Key_VolumeDown) {
      processKeyEvent(key, ev);
    }
  }

  return QObject::eventFilter(obj, event);
}

bool DeviceKeys::isActive() const {
  return m_active;
}

void DeviceKeys::setActive(bool active) {
  if (m_active != active) {
    m_active = active;
    emit activeChanged();
  }
}

bool DeviceKeys::isRepeating() {
  return m_repeating;
}

void DeviceKeys::doRepeat(bool repeat) {
  if (repeat != m_repeating) {
    m_repeating = repeat;
    emit repeatChanged();
  }
}

void DeviceKeys::processKeyEvent(int key, int event) {
  if (event == QEvent::KeyPress && key == Qt::Key_VolumeUp) {
    emit volumeUpPressed();
  } else if (event == QEvent::KeyRelease && key == Qt::Key_VolumeUp) {
    emit volumeUpReleased();
  } else if (event == QEvent::KeyPress && key == Qt::Key_VolumeDown) {
    emit volumeDownPressed();
  } else if (event == QEvent::KeyRelease && key == Qt::Key_VolumeDown) {
    emit volumeDownReleased();
  } else {
    return;
  }

  if (!m_repeating) {
    m_timer->stop();
  }

  if (event == QEvent::KeyRelease) {
    m_timer->stop();
  }

  m_event = event;
  m_key = key;

  m_timer->start();
}

void DeviceKeys::repeatEventsIfNeeded() {
  if (m_event != 0 && m_key != 0 && m_repeating) {
    processKeyEvent(m_key, m_event);
  }
  else {
    m_timer->stop();
  }
}
<commit_msg>sailfish: decrease key repeat timer timeout to 75ms instead of 100ms<commit_after>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "devicekeys.h"
#include <QGuiApplication>
#include <QDebug>
#include <QEvent>
#include <QKeyEvent>
#include <QTimer>
#include <QWindow>

#define KEY_REPEAT_TIMEOUT 75

DeviceKeys::DeviceKeys(QObject *parent) :
  QObject(parent),
  m_repeating(true),
  m_active(false),
  m_timer(new QTimer(this)),
  m_event(0),
  m_key(0) {

  m_timer->setInterval(KEY_REPEAT_TIMEOUT);
  m_timer->setSingleShot(false);

  QObject::connect(m_timer, SIGNAL(timeout()), this, SLOT(repeatEventsIfNeeded()));

  QGuiApplication::instance()->installEventFilter(this);
}

DeviceKeys::~DeviceKeys() {

}

bool DeviceKeys::eventFilter(QObject *obj, QEvent *event) {
  if (!m_active) {
    return QObject::eventFilter(obj, event);
  }

  QWindow *win = dynamic_cast<QWindow *>(obj);
  if (!win || !QGuiApplication::allWindows().contains(win)) {
    return QObject::eventFilter(obj, event);
  }

  int ev = event->type();
  if (ev == QEvent::KeyPress || ev == QEvent::KeyRelease) {
    QKeyEvent *e = dynamic_cast<QKeyEvent *>(event);
    int key = e->key();

    if (key == Qt::Key_VolumeUp || key == Qt::Key_VolumeDown) {
      processKeyEvent(key, ev);
    }
  }

  return QObject::eventFilter(obj, event);
}

bool DeviceKeys::isActive() const {
  return m_active;
}

void DeviceKeys::setActive(bool active) {
  if (m_active != active) {
    m_active = active;
    emit activeChanged();
  }
}

bool DeviceKeys::isRepeating() {
  return m_repeating;
}

void DeviceKeys::doRepeat(bool repeat) {
  if (repeat != m_repeating) {
    m_repeating = repeat;
    emit repeatChanged();
  }
}

void DeviceKeys::processKeyEvent(int key, int event) {
  if (event == QEvent::KeyPress && key == Qt::Key_VolumeUp) {
    emit volumeUpPressed();
  } else if (event == QEvent::KeyRelease && key == Qt::Key_VolumeUp) {
    emit volumeUpReleased();
  } else if (event == QEvent::KeyPress && key == Qt::Key_VolumeDown) {
    emit volumeDownPressed();
  } else if (event == QEvent::KeyRelease && key == Qt::Key_VolumeDown) {
    emit volumeDownReleased();
  } else {
    return;
  }

  if (!m_repeating) {
    m_timer->stop();
  }

  if (event == QEvent::KeyRelease) {
    m_timer->stop();
  }

  m_event = event;
  m_key = key;

  m_timer->start();
}

void DeviceKeys::repeatEventsIfNeeded() {
  if (m_event != 0 && m_key != 0 && m_repeating) {
    processKeyEvent(m_key, m_event);
  }
  else {
    m_timer->stop();
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SAK_OBJECT_REGISTRY_HPP
#define SAK_OBJECT_REGISTRY_HPP

#include <map>

#include <boost/function.hpp>

#include "object_factory_impl.hpp"

namespace sak
{

    /// Object registry used to store factories to construct objects of
    /// the registered types.
    class object_registry
    {
    private:

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object_factory> >
            factory_map;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object> >
            object_map;

    public:

        /// Constructor of the factory registry
        object_registry()
            { }

        /// @return a factory stored in the registry
        template<class Factory>
        boost::shared_ptr<Factory> get_factory()
            {
                auto factory_id = get_object_id<Factory>();
                auto factory = find(m_lookup_by_factory_id, factory_id);

                assert(factory);

                typedef object_factory_impl<Factory> factory_type;

                auto factory_impl =
                    boost::dynamic_pointer_cast<factory_type>(factory);

                assert(factory_impl);
                assert(factory_impl->m_factory);
                return factory_impl->m_factory;
            }

        /// Registers an object factory with the object registry
        /// Once a factory has been registered objects can be created
        template<class Factory, class Object>
        void set_factory()
            {
                auto factory_id = get_object_id<Factory>();
                auto object_id  = get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(factory_id.m_id != object::id()->m_id);

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_impl<Factory> >();

                m_lookup_by_factory_id[factory_id] = factory;
                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory function with the object registry
        /// Once a factory function has been registered objects can be created
        template<class Object>
        void set_factory(const boost::function<boost::shared_ptr<Object>(
                             object_registry &)> &function)
            {
                auto object_id = get_object_id<Object>();

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_function<Object> >(function);

                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory with the object registry. This methods
        /// can be used for factories with a non-standard build function.
        /// Users can call the get function and invoke the custom build function
        template<class Object>
        void set_object()
            {
                auto object_id = get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(object_id.m_id != object::id()->m_id);

                auto object = boost::make_shared<Object>();

                m_lookup_by_shared_object_id[object_id] = object;
            }

        /// @return a factory stored in the registry
        template<class Object>
        boost::shared_ptr<Object> get_object()
            {
                auto object_id = get_object_id<Object>();
                auto object = find(m_lookup_by_shared_object_id, object_id);

                assert(object);
                return boost::dynamic_pointer_cast<Object>(object);
            }

        /// Clears all registered factories
        void clear_factories()
            {
                m_lookup_by_factory_id.clear();
                m_lookup_by_object_id.clear();
            }

        /// @return an object created using the registered factories
        template<class Object>
        boost::shared_ptr<Object> build()
            {
                assert(has_object_id(m_lookup_by_object_id, *Object::id()));

                auto factory =
                    find(m_lookup_by_object_id, *Object::id());

                assert(factory);

                auto object = factory->build(*this);

                return boost::dynamic_pointer_cast<Object>(object);
            }

    private:

        /// Checks if an object id is registered in a specific category
        template<class Map>
        bool has_object_id(const Map &map, const object_id &id) const
            {
                return map.find(id) != map.end();
            }

        /*template<class Object>
        object_id get_object_id() const
            {
                return *Object::id();
            }*/

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object_factory>
        find(const factory_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object>
        find(const object_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

    private:

        /// Map allowing a factory to be found based on an object's object id
        factory_map m_lookup_by_object_id;

        /// Map allowing a shared object to be found based on an object's object id
        object_map m_lookup_by_shared_object_id;

        /// Map allowing a factory to be found based on a factory's object id
        factory_map m_lookup_by_factory_id;

    };

    /// Template must be specialized by all object classes used with the object registry
    template<class Object> object_id get_object_id();
}

#endif

<commit_msg>fixing pointer<commit_after>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Steinwurf ApS nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Steinwurf ApS BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#ifndef SAK_OBJECT_REGISTRY_HPP
#define SAK_OBJECT_REGISTRY_HPP

#include <map>

#include <boost/function.hpp>

#include "object_factory_impl.hpp"

namespace sak
{

    /// Object registry used to store factories to construct objects of
    /// the registered types.
    class object_registry
    {
    private:

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object_factory> >
            factory_map;

        /// The map associating an object id to an object factory
        typedef std::map<object_id, boost::shared_ptr<object> >
            object_map;

    public:

        /// Constructor of the factory registry
        object_registry()
            { }

        /// @return a factory stored in the registry
        template<class Factory>
        boost::shared_ptr<Factory> get_factory()
            {
                auto factory_id = *get_object_id<Factory>();
                auto factory = find(m_lookup_by_factory_id, factory_id);

                assert(factory);

                typedef object_factory_impl<Factory> factory_type;

                auto factory_impl =
                    boost::dynamic_pointer_cast<factory_type>(factory);

                assert(factory_impl);
                assert(factory_impl->m_factory);
                return factory_impl->m_factory;
            }

        /// Registers an object factory with the object registry
        /// Once a factory has been registered objects can be created
        template<class Factory, class Object>
        void set_factory()
            {
                auto factory_id = *get_object_id<Factory>();
                auto object_id  = *get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(factory_id.m_id != object::id()->m_id);

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_impl<Factory> >();

                m_lookup_by_factory_id[factory_id] = factory;
                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory function with the object registry
        /// Once a factory function has been registered objects can be created
        template<class Object>
        void set_factory(const boost::function<boost::shared_ptr<Object>(
                             object_registry &)> &function)
            {
                auto object_id = *get_object_id<Object>();

                // Did you forget to make the id function in the class Object?
                assert(object_id.m_id != object::id()->m_id);

                auto factory =
                    boost::make_shared< object_factory_function<Object> >(function);

                m_lookup_by_object_id[object_id] = factory;
            }

        /// Registers an object factory with the object registry. This methods
        /// can be used for factories with a non-standard build function.
        /// Users can call the get function and invoke the custom build function
        template<class Object>
        void set_object()
            {
                auto object_id = *get_object_id<Object>();

                // Did you forget to make the id function in the class Factory?
                assert(object_id.m_id != object::id()->m_id);

                auto object = boost::make_shared<Object>();

                m_lookup_by_shared_object_id[object_id] = object;
            }

        /// @return a factory stored in the registry
        template<class Object>
        boost::shared_ptr<Object> get_object()
            {
                auto object_id = *get_object_id<Object>();
                auto object = find(m_lookup_by_shared_object_id, object_id);

                assert(object);
                return boost::dynamic_pointer_cast<Object>(object);
            }

        /// Clears all registered factories
        void clear_factories()
            {
                m_lookup_by_factory_id.clear();
                m_lookup_by_object_id.clear();
            }

        /// @return an object created using the registered factories
        template<class Object>
        boost::shared_ptr<Object> build()
            {
                assert(has_object_id(m_lookup_by_object_id, *Object::id()));

                auto factory =
                    find(m_lookup_by_object_id, *Object::id());

                assert(factory);

                auto object = factory->build(*this);

                return boost::dynamic_pointer_cast<Object>(object);
            }

    private:

        /// Checks if an object id is registered in a specific category
        template<class Map>
        bool has_object_id(const Map &map, const object_id &id) const
            {
                return map.find(id) != map.end();
            }

        /*template<class Object>
        object_id get_object_id() const
            {
                return *Object::id();
            }*/

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object_factory>
        find(const factory_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

        /// Finds and returns an object factory in the given map with a
        /// "compatible" object_id.
        boost::shared_ptr<object>
        find(const object_map &map, const object_id &id) const
            {
                assert(has_object_id(map,id));
                return map.at(id);
            }

    private:

        /// Map allowing a factory to be found based on an object's object id
        factory_map m_lookup_by_object_id;

        /// Map allowing a shared object to be found based on an object's object id
        object_map m_lookup_by_shared_object_id;

        /// Map allowing a factory to be found based on a factory's object id
        factory_map m_lookup_by_factory_id;

    };

    /// Template must be specialized by all object classes used with the object registry
    template<class Object> object_id* get_object_id();
}

#endif

<|endoftext|>


<commit_before>#ifndef NETWORK_CONNECTION_HPP
#define NETWORK_CONNECTION_HPP

#include<string>
#include<functional>
#include<boost/asio.hpp>
#include<memory>
#include<mutex>
#include<string>
#include<thread>
#include<condition_variable>
#include<atomic>

using boost::asio::ip::tcp;

namespace network {

	using ResponseHandler = std::function<void(std::string)>;
	using SocketP = std::shared_ptr<tcp::socket>;
	using ULock = std::unique_lock<std::recursive_mutex>;

	/**
		* @brief A representation of a single network connection to which you can write
		* and from which you can read.
		* @todo Add a constructor for creating accepting connections.
		* @todo Implement all the functions.
		*/
	class Connection {
		public:
			static boost::asio::io_service io_service;
			Connection(SocketP sockpointer);
			/**
				* @brief Destroys the object and closes the connection.
				*/
			~Connection();

			/**
				* @brief Returns whether the connection has been in some way closed and will
				* get no more messages.
				*/
			bool isClosed() const;

			/**
				* @brief Sets a function to call after we got the next full response.
				* @param[in] handler The function to handle the response.
				* @return Whether it was possible to set the handler -- it is impossible if
				* the Connection is currently used for some other communication.
				*/
			bool setResponseHandler(ResponseHandler handler);

			/**
				* @brief Sends the specified message to the other side of this connection.
				* @param[in] message The message to be send.
				* @param[in] handler The handler to set for receiving responces after
				* sending the message. This should be empty, if no response is anticipated.
				* @return Whether it was possible to send the message -- it is impossible if
				* the Connection is currently used for some other communication.
				*/
			bool sendMessage(std::string message, ResponseHandler handler);

			/**
				* @brief Blocks until the next communication sequence ends or the connection
				* is closed for some reason.
				*/
			void wait();

			/**
				* @brief Closes the connection.
				*/
			void close();

			/**
				* @brief Create a connection to the specified address.
				* @param[in] address The address to which to connect.
				* @todo Either specify properly the format of the address string or change
				* the arguments for this function and then specify it anyway, but for the
				* new arguments.
				*/
			static std::shared_ptr<Connection> connectTo(std::string address, std::string portNumber);
			static void runAll();
		private:
			static void runIOservice();
			static boost::asio::io_service::work work;
			static std::shared_ptr<std::thread> netThread;
			void sendHandler(const boost::system::error_code& err, std::size_t bytes_transferred, ResponseHandler handler);
			void execResponseHandler(const boost::system::error_code& err, std::size_t bytes_transferred);
			SocketP sockPointer;
			ResponseHandler	curHandler;
			std::recursive_mutex mtx;
			std::condition_variable_any cv;
			std::atomic<int> dreamLevel;

			static const int BUF_SIZE = 2048;
			char buffer[BUF_SIZE];
	};
}

#endif
<commit_msg>Connection documentation<commit_after>#ifndef NETWORK_CONNECTION_HPP
#define NETWORK_CONNECTION_HPP

#include<string>
#include<functional>
#include<boost/asio.hpp>
#include<memory>
#include<mutex>
#include<string>
#include<thread>
#include<condition_variable>
#include<atomic>

using boost::asio::ip::tcp;

namespace network {

	using ResponseHandler = std::function<void(std::string)>;
	using SocketP = std::shared_ptr<tcp::socket>;
	using ULock = std::unique_lock<std::recursive_mutex>;

	/**
		* @brief A representation of a single network connection to which you can write
		* and from which you can read.
		* @todo Add a constructor for creating accepting connections.
		* @todo Implement all the functions.
		*/
	class Connection {
		public:
			/**
				* @brief Takes care whole network services.
				*/
			static boost::asio::io_service io_service;

			/**
				* @brief Constructs object from specified socket.
				*/
			Connection(SocketP sockpointer);

			/**
				* @brief Destroys the object and closes the connection.
				*/
			~Connection();

			/**
				* @brief Returns whether the connection has been in some way closed and will
				* get no more messages.
				*/
			bool isClosed() const;

			/**
				* @brief Sets a function to call after we got the next full response.
				* @param[in] handler The function to handle the response.
				* @return Whether it was possible to set the handler -- it is impossible if
				* the Connection is currently used for some other communication.
				*/
			bool setResponseHandler(ResponseHandler handler);

			/**
				* @brief Sends the specified message to the other side of this connection.
				* @param[in] message The message to be send.
				* @param[in] handler The handler to set for receiving responces after
				* sending the message. This should be empty, if no response is anticipated.
				* @return Whether it was possible to send the message -- it is impossible if
				* the Connection is currently used for some other communication.
				*/
			bool sendMessage(std::string message, ResponseHandler handler);

			/**
				* @brief Blocks until the next communication sequence ends or the connection
				* is closed for some reason.
				*/
			void wait();

			/**
				* @brief Closes the connection.
				*/
			void close();

			/**
				* @brief Create a connection to the specified address.
				* @param[in] address The address to which to connect.
				* @todo Either specify properly the format of the address string or change
				* the arguments for this function and then specify it anyway, but for the
				* new arguments.
				*/
			static std::shared_ptr<Connection> connectTo(std::string address, std::string portNumber);

			/**
				* @brief Run io_service and start all connections.
				*/
			static void runAll();
		private:
			static void runIOservice();
			static boost::asio::io_service::work work;
			static std::shared_ptr<std::thread> netThread;
			void sendHandler(const boost::system::error_code& err, std::size_t bytes_transferred, ResponseHandler handler);
			void execResponseHandler(const boost::system::error_code& err, std::size_t bytes_transferred);
			SocketP sockPointer;
			ResponseHandler	curHandler;
			std::recursive_mutex mtx;
			std::condition_variable_any cv;
			std::atomic<int> dreamLevel;

			static const int BUF_SIZE = 2048;
			char buffer[BUF_SIZE];
	};
}

#endif
<|endoftext|>