view anagram/guisupport/action.h @ 15:f5acaf0c8a29

Don't cast through "volatile int". Causes a gcc warning nowadays. XXX: should put something else back here to frighten the optimizer
author David A. Holland
date Tue, 31 May 2022 01:00:55 -0400
parents 13d2b8934445
children
line wrap: on
line source

/*
 * AnaGram, A System for Syntax Directed Programming
 * Copyright 1997-2002 Parsifal Software. All Rights Reserved.
 * See the file COPYING for license and usage terms.
 *
 * action.h
 */

#ifndef ACTION_H
#define ACTION_H

#include "agstack.h"


class AgAction {
public:

  class Kernel {
  private:
    int useCount;
  public:
    virtual ~Kernel() {}
    virtual void perform() const = 0;
    
    Kernel() : useCount(0) {}
    void lock() { useCount++; }
    int unlock() { return --useCount <= 0; }
  };

protected:
  Kernel *kernel;
  static int running;

  static AgStack<AgAction> startupStack;

public:
  AgAction() : kernel(0) {}
  AgAction(AgAction::Kernel *kernel_) : kernel(kernel_) {
    if (kernel) {
      kernel->lock();
    }
  }
  AgAction(const AgAction &a) : kernel(a.kernel) {
    if (kernel) {
      kernel->lock();
    }
  }
  AgAction &operator = (const AgAction &a) {
    if (kernel && kernel->unlock()) {
      delete kernel;
    }
    kernel = a.kernel;
    if (kernel) {
      kernel->lock();
    }
    return *this;
  }
  ~AgAction() {
    if (kernel && kernel->unlock()) {
      delete kernel;
      kernel = 0;
    }
  }
  int exists() { return kernel != 0; }
  void perform() const { if (kernel) kernel->perform(); }
  void operator () () const { if (kernel) kernel->perform(); }
  //void defer() const;
  void performDeferred() const;
  static void startup();
  int operator < (const AgAction &a) const { return this < &a; }
};


template<class T>
class AgClassAction : public AgAction {
private:

  class Kernel : public AgAction::Kernel {
  private:
    T &object;
    void (T:: * memberFunction)();

  public:
    Kernel(T &object_, void (T:: * memberFunction_)()) :
      object(object_) ,
      memberFunction(memberFunction_)
    {}
    void perform() const {(object.*memberFunction)();}
  };

public:
  AgClassAction(T &object_, void (T:: * memberFunction_)()) :
    AgAction(new AgClassAction<T>::Kernel(object_,memberFunction_))
  {}
  AgClassAction(const AgClassAction<T> &a) :
    AgAction(a)
  {}
};

template <class T>
AgAction actionObject(T *t, void (T:: * memberFunction)()) {
  return AgClassAction<T>(*t, memberFunction);
}

void defer(void (*f)());

template <class T>
void defer(T *t, void (T:: * memberFunction)()) {
  AgClassAction<T>(*t, memberFunction).performDeferred();
}

class AgSimpleAction : public AgAction {
private:

  class Kernel : public AgAction::Kernel {
    void (* function)();
  public:
    Kernel(void (* function_)()) :
      function(function_)
    {}
    void perform() const {(*function)();}
  };

public:
  AgSimpleAction(void (* function_)()) :
    AgAction(new AgSimpleAction::Kernel(function_))
  {}
  AgSimpleAction(const AgSimpleAction &a) :
    AgAction(a)
  {}
};

AgAction actionObject(void (* function)());


////////////////////////////////////////////////////////////
//
// interaction with GUI event loop

// this must be provided by the GUI - see e.g. vaclgui/actionwin.cpp
// (not defined in action.cpp)
void AgActionEnqueueInGui(AgAction::Kernel *kernel);

// and the GUI should hand the object back to this function.
void AgActionDispatchFromGui(AgAction::Kernel *kernel);


#endif /* ACTION_H */