lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Laurent FAILLIE once stated:
> Hello,
> I'm working to a graphical framework in C dealing with Cairo graphics.
> I'm creating an object named SelDCSurface that deals with Cairo's surface
> https://github.com/destroyedlolo/Selene/blob/v6/src/SelPlugins/DRMCairo/SelDCSurface.c
> Some methods are attached to it using luaL_setfuncs() or luaL_register().
> Now, I'm working on SelDCImageSurface which is basically an extension of SelDCSurface : it has to know all methods of SelDCSurface plus its own.
> 1/ How to do that ?I guess I can use luaL_setfuncs() or luaL_register() more than once on the same object, to add additional methods, isn't it ?

  I have a "work-when-I-get-to-it-in-progress" wrapping Xlib [1] and I
solved that problem by just including the additional methods into the table:

static const luaL_Reg xpixmap_meta[] =
{
  { "__index"           , x___index                } ,
  { "__newindex"        , x___newindex             } ,
  { "__gc"              , xpixmap___gc             } ,
  { "__tostring"        , xpixmap___tostring       } ,
  { "copy"              , xdrawable_copy           } ,
  { "draw_arc"          , xdrawable_draw_arc       } ,
  { "draw_fill_arc"     , xdrawable_draw_fill_arc  } ,
  { "draw_fill_rect"    , xdrawable_draw_fill_rect } ,
  { "draw_line"         , xdrawable_draw_line      } ,
  { "draw_point"        , xdrawable_draw_point     } ,
  { "draw_rect"         , xdrawable_draw_rect      } ,
  { "draw_string"       , xdrawable_draw_string    } ,
  { "gc"                , xdrawable_gc             } , /* Graphics Context */
  { NULL                , NULL                     }
};

static const luaL_Reg xwindow_meta[] =
{
  { "__index"           , x___index                } ,
  { "__newindex"        , x___newindex             } ,
  { "__gc"              , xwindow___gc             } ,
  { "__tostring"        , xwindow___tostring       } ,
  { "attributes"        , xwindow_attributes       } ,
  { "background"        , xwindow_background       } ,
  { "checkevent"        , xwindow_checkevent       } ,
  { "clear"             , xwindow_clear            } ,
  { "copy"              , xdrawable_copy           } ,
  { "cursor"            , xwindow_cursor           } ,
  { "dimensions"        , xwindow_dimensions       } ,
  { "draw_arc"          , xdrawable_draw_arc       } ,
  { "draw_fill_arc"     , xdrawable_draw_fill_arc  } ,
  { "draw_fill_rect"    , xdrawable_draw_fill_rect } ,
  { "draw_line"         , xdrawable_draw_line      } ,
  { "draw_point"        , xdrawable_draw_point     } ,
  { "draw_rect"         , xdrawable_draw_rect      } ,
  { "draw_string"       , xdrawable_draw_string    } ,
  { "focus"             , xwindow_focus            } ,
  { "gc"                , xdrawable_gc             } ,
  { "hide"              , xwindow_hide             } ,
  { "listproperties"    , xwindow_listproperties   } ,
  { "lower"             , xwindow_lower            } ,
  { "move"              , xwindow_move             } ,
  { "moveresize"        , xwindow_moveresize       } ,
  { "raise"             , xwindow_raise            } ,
  { "resize"            , xwindow_resize           } ,
  { "seticon"           , xwindow_seticon          } ,
  { "seticonname"       , xwindow_seticonname      } ,
  { "setname"           , xwindow_setname          } ,
  { "show"              , xwindow_show             } ,
  { "showsub"           , xwindow_showsub          } ,
  { "sizehints"         , xwindow_sizehints        } ,
  { "wmhints"           , xwindow_wmhints          } ,
  { "wmprotocol"        , xwindow_wmprotocol       } ,
  { NULL                , NULL                     }
};

  I suppose multiple tables and using luaL_setfuncs()/luaL_register()
multiple times could work.  In my case, it would have to be one table for
the metamethods, and one each for the non-metamethods to be included.

> 2/ my main concern is the function used if "self" object has the right type
> I.E. for method

  [ snip ]

> The problem, is when called from a SelDCImageSurface object, GetSize() will still call checkSelDCSurface() which fails as facing a "SelDCImageSurface" and not a "SelDCSurface".
> Any smart way to avoid that ?

  I ended up writing my own functions to handle an object that could be
different types:

static bool XL_isudata(lua_State *const L,int idx,const char *const tname)
{
  assert(L     != NULL);
  assert(idx   != 0);
  assert(tname != NULL);
  
  void *p = lua_touserdata(L,idx);
  if (p != NULL)
  {
    if (lua_getmetatable(L,idx))
    {
      const char *type;
      bool        rc;

      lua_getfield(L,-1,"_TYPE");
      type = lua_tostring(L,-1);
      rc   = strcmp(type,tname) == 0;
      lua_pop(L,2);
      return rc;
    }
  }
  return false;
}

static void *XL_multiudata(lua_State *const L,int idx, ... )
{
  void    *tname;
  va_list  ap;
  
  assert(L   != NULL);
  assert(idx != 0);
  
  va_start(ap,idx);
  
  while((tname = va_arg(ap,void *)) != NULL)
  {
    if (XL_isudata(L,idx,tname))
    {
      va_end(ap);
      return lua_touserdata(L,idx);
    }
  }
  
  va_end(ap);
  luaL_error(L,"wrong type of data");
  return NULL;
}

  And to use it:

	Drawable drawable = XL_multiudata(L,1,XLUA_WINDOW,XLUA_PIXMAP,NULL);

  That's how I solved the issue.

  -spc

[1]	No, it's not in any state to release right now and is mostly for my
	own amusement.