*** empty log message ***
[m17n/m17n-lib.git] / src / m17n-gui.c
index b752f1b..287988c 100644 (file)
 #include "fontset.h"
 #include "face.h"
 
-static int win_initialized;
-
 #ifndef DLOPEN_SHLIB_EXT
 #define DLOPEN_SHLIB_EXT ".so"
 #endif
 
+/** Information about a dynamic library supporting a specific graphic
+    device.  */
+typedef struct
+{
+  /** Name of the dynamic library (e.g. "libm17n-X.so").  */
+  char *library;
+  /** Handle fo the dynamic library.  */
+  void *handle;
+  /** Function to call just after loading the library.  */
+  int (*init) ();
+  /** Function to call to open a frame on the graphic device.  */
+  int (*open) (MFrame *frame, MPlist *param);
+  /** Function to call just before unloading the library.  */
+  int (*fini) ();
+} MDeviceLibraryInterface;
+
+
+/** Plist of device symbol vs MDeviceLibraryInterface.  */
+
+static MPlist *device_library_list;
+
 /** Close MFrame and free it.  */
 
 static void
@@ -99,6 +118,24 @@ free_frame (void *object)
   free (object);
 }
 
+
+/** Register a dynamic library of name LIB by a key NAME.  */
+
+static int
+register_device_library (MSymbol name, char *lib)
+{
+  MDeviceLibraryInterface *interface;
+
+  MSTRUCT_CALLOC (interface, MERROR_WIN);
+  interface->library = malloc (strlen (lib) 
+                              + strlen (DLOPEN_SHLIB_EXT) + 1);
+  sprintf (interface->library, "%s%s", lib, DLOPEN_SHLIB_EXT);
+  if (! device_library_list)
+    device_library_list = mplist ();
+  mplist_add (device_library_list, name, interface);
+  return 0;
+}
+
 \f
 #ifdef HAVE_FREETYPE
 /** Null device support.  */
@@ -109,6 +146,36 @@ static struct {
   MPlist *realized_face_list;
 } null_device;
 
+static void
+null_device_close (MFrame *frame)
+{
+}
+
+static void *
+null_device_get_prop (MFrame *frame, MSymbol key)
+{
+  return NULL;
+}
+
+static void
+null_device_realize_face (MRealizedFace *rface)
+{
+  rface->info = NULL;
+}
+
+static void
+null_device_free_realized_face (MRealizedFace *rface)
+{
+}
+
+static MDeviceDriver null_driver =
+  {
+    null_device_close,
+    null_device_get_prop,
+    null_device_realize_face,
+    null_device_free_realized_face
+  };
+
 static int
 null_device_init ()
 {
@@ -144,6 +211,7 @@ null_device_open (MFrame *frame, MPlist *param)
 
   frame->device = NULL;
   frame->device_type = 0;
+  frame->driver = &null_driver;
   frame->font_driver_list = mplist ();
   mplist_add (frame->font_driver_list, Mfreetype, &mfont__ft_driver);
   frame->realized_font_list = null_device.realized_font_list;
@@ -155,74 +223,37 @@ null_device_open (MFrame *frame, MPlist *param)
   return 0;
 }
 
-static void
-null_device_close (MFrame *frame)
-{
-}
-
-static void *
-null_device_get_prop (MFrame *frame, MSymbol key)
-{
-  return NULL;
-}
-
-static void
-null_device_realize_face (MRealizedFace *rface)
-{
-  rface->info = NULL;
-}
-
-static void
-null_device_free_realized_face (MRealizedFace *rface)
-{
-}
-
-static MDeviceDriver null_driver =
-  {
-    0,
-    null_device_init,
-    null_device_fini,
-    null_device_open,
-    null_device_close,
-    null_device_get_prop,
-    null_device_realize_face,
-    null_device_free_realized_face
-  };
+static MDeviceLibraryInterface null_interface =
+  { NULL, NULL, null_device_init, null_device_open, null_device_fini };
 
 #endif
 \f
 /* Internal API */
 
-MSymbol Mfreetype;
-
-/** Plist of device symbol vs functions to initialized the device
-    library.  */
-MPlist *m17n__device_library_list;
-
-
 /*** @} */ 
 #endif /* !FOR_DOXYGEN || DOXYGEN_INTERNAL_MODULE */
 
 \f
 /* External API */
 
-int
+void
 m17n_init_win (void)
 {
   int mdebug_mask = MDEBUG_INIT;
 
-  if (win_initialized++)
-    return 0;
+  if (m17n__gui_initialized++)
+    return;
   m17n_init ();
   if (merror_code != MERROR_NONE)
-    return -1;
+    {
+      m17n__gui_initialized--;
+      return;
+    }
 
   MDEBUG_PUSH_TIME ();
 
-  Mx = msymbol ("x");
   Mgd = msymbol ("gd");
 
-  Mfreetype = msymbol ("freetype");
   Mfont = msymbol ("font");
   Mfont_width = msymbol ("font-width");
   Mfont_ascent = msymbol ("font-ascent");
@@ -253,62 +284,59 @@ m17n_init_win (void)
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize input-win module."));
   mframe_default = NULL;
 
-  m17n__device_library_list = mplist ();
-#ifdef HAVE_FREETYPE
-  null_driver.initialized = 0;
-  mplist_put (m17n__device_library_list, Mt, &null_driver);
-#endif
-
-  return 0;
+  register_device_library (Mx, "libm17n-X");
+  register_device_library (Mgd, "libm17n-gd");
+  return;
 
  err:
   MDEBUG_POP_TIME ();
   MDEBUG_PRINT_TIME ("INIT", (stderr, " to initialize the m17n GUI module."));
   MDEBUG_POP_TIME ();
-  return -1;
 }
 
 void
 m17n_fini_win (void)
 {
   int mdebug_mask = MDEBUG_FINI;
+  MPlist *plist;
 
-  if (win_initialized > 1)
-    win_initialized--;
-  else
+  if (m17n__gui_initialized == 0
+      || --m17n__gui_initialized > 0)
+    return;
+
+  MDEBUG_PUSH_TIME ();
+  MDEBUG_PUSH_TIME ();
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize device modules."));
+  MPLIST_DO (plist, device_library_list)
     {
-      MPlist *plist;
+      MDeviceLibraryInterface *interface = MPLIST_VAL (plist);
 
-      win_initialized = 0;
-      MDEBUG_PUSH_TIME ();
-      MDEBUG_PUSH_TIME ();
-      MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize device modules."));
-      MPLIST_DO (plist, m17n__device_library_list)
+      if (interface->handle && interface->fini)
        {
-         MDeviceDriver *driver = MPLIST_VAL (plist);
-
-         if (driver->initialized)
-           {
-             (*driver->fini) ();
-             driver->initialized = 0;
-           }
+         (*interface->fini) ();
+         dlclose (interface->handle);
        }
-      M17N_OBJECT_UNREF (m17n__device_library_list);
-      MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize input-gui module."));
-      minput__win_fini ();
-      MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize draw module."));
-      mdraw__fini ();
-      MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize face module."));
-      mface__fini ();
-      MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize fontset module."));
-      mfont__fontset_fini ();
-      MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize font module."));
-      mfont__fini ();
-      mframe_default = NULL;
-      MDEBUG_POP_TIME ();
-      MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the gui modules."));
-      MDEBUG_POP_TIME ();
+      free (interface->library);
     }
+#ifdef HAVE_FREETYPE
+  if (null_interface.handle)
+    (*null_interface.fini) ();
+#endif /* not HAVE_FREETYPE */
+  M17N_OBJECT_UNREF (device_library_list);
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize input-gui module."));
+  minput__win_fini ();
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize draw module."));
+  mdraw__fini ();
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize face module."));
+  mface__fini ();
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize fontset module."));
+  mfont__fontset_fini ();
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize font module."));
+  mfont__fini ();
+  mframe_default = NULL;
+  MDEBUG_POP_TIME ();
+  MDEBUG_PRINT_TIME ("FINI", (stderr, " to finalize the gui modules."));
+  MDEBUG_POP_TIME ();
   m17n_fini ();
 }
 
@@ -352,7 +380,7 @@ m17n_fini_win (void)
 
 MSymbol Mdevice, Mdisplay, Mscreen, Mdrawable, Mdepth, Mcolormap, Mwidget; 
 
-MSymbol Mx, Mgd;
+MSymbol Mgd;
 
 /*=*/
 
@@ -463,6 +491,19 @@ MSymbol Mfont_descent;
 
     The created frame uses the specified colormap.
 
+    <li> #Mfont, the value must be #Mx, #Mfreetype, or #Mxft.
+
+    The created frame uses the specified font backend.  The value #Mx
+    instructs to use X core fonts, #Mfreetype to use local fonts
+    supported by FreeType fonts, and #Mxft to use local fonts via Xft
+    library.  You can specify this parameter more than once with
+    different values if you want to use multiple font backends.  This
+    is ignored if the specified font backend is not supported on the
+    device.
+    
+    When this parameter is not specified, all font backend supported
+    on the device are used.
+
     </ul>
 
     @return
@@ -551,6 +592,19 @@ MSymbol Mfont_descent;
 
     À¸À®¤µ¤ì¤¿¥Õ¥ì¡¼¥à¤Ï¡¢»ØÄꤷ¤¿¥«¥é¡¼¥Þ¥Ã¥×¤ò»ÈÍѤ¹¤ë¡£
 
+    <li> #Mfont. Ãͤϡ¢#Mx, #Mfreetype, #Mxft ¤Î¤¤¤º¤ì¤«¡£
+
+    À¸À®¤µ¤ì¤¿¥Õ¥ì¡¼¥à¤Ï»ØÄꤷ¤¿¥Õ¥©¥ó¥È¥Ð¥Ã¥¯¥¨¥ó¥É¤ò»ÈÍѤ¹¤ë¡£Ãͤ¬ 
+    #Mx ¤Ç¤¢¤ì¤Ð X ¤Î¥³¥¢¥Õ¥©¥ó¥È¡¢#Mfreetype ¤Ç¤¢¤ì¤Ð FreeType ¤Ç¥µ¥Ý¡¼
+    ¥È¤µ¤ì¤Æ¤¤¤ë¥í¡¼¥«¥ë¥Õ¥©¥ó¥È¡¢#Mxft ¤Ç¤¢¤ì¤Ð Xft ¥é¥¤¥Ö¥é¥ê·Ðͳ¤Ç
+    ÍѤ¤¤ë¥í¡¼¥«¥ë¥Õ¥©¥ó¥È¤ò»ÈÍѤ¹¤ë¡£Ê£¿ô¤Î¥Õ¥©¥ó¥È¥Ð¥Ã¥¯¥¨¥ó¥É¤ò»ÈÍÑ
+    ¤·¤¿¤¤¾ì¹ç¤Ë¤Ï¡¢¤³¤Î¥Ñ¥é¥á¡¼¥¿¤òÊ£¿ô²ó¡¢°Û¤Ê¤ëÃͤǻØÄꤹ¤ë¤³¤È¤¬¤Ç
+    ¤­¤ë¡£»ØÄꤷ¤¿¥Ð¥Ã¥¯¥¨¥ó¥É¤¬¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Ê¤¤¥Ç¥Ð¥¤¥¹¤Ç¤Ï¡¢¤³¤Î
+    ¥Ñ¥é¥á¡¼¥¿¤Ï̵»ë¤µ¤ì¤ë¡£
+
+    ¤³¤Î¥Ñ¥é¥á¡¼¥¿¤¬Ìµ¤¤¾ì¹ç¤Ë¤Ï¡¢¥Ç¥Ð¥¤¥¹¤Ç¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤ë¤¹¤Ù¤Æ¤Î
+    ¥Õ¥©¥ó¥È¥Ð¥Ã¥¯¥¨¥ó¥É¤òÍøÍѤ¹¤ë¡£
+
     </ul>
 
     @return
@@ -564,19 +618,13 @@ mframe (MPlist *plist)
   int plist_created = 0;
   MPlist *pl;
   MSymbol device;
-  MDeviceDriver *driver;
+  MDeviceLibraryInterface *interface;
 
   if (plist)
     {
       pl = mplist_find_by_key (plist, Mdevice);
       if (pl)
-       {
-         device = MPLIST_VAL (pl);
-         if (device == Mt)
-           MERROR (MERROR_WIN, NULL);
-         if (device == Mnil)
-           device = Mt;
-       }
+       device = MPLIST_VAL (pl);
       else
        device = Mx;
     }
@@ -587,23 +635,46 @@ mframe (MPlist *plist)
       device = Mx;
     }
 
-  driver = mplist_get (m17n__device_library_list, device);
-  if (! driver)
-    MERROR (MERROR_WIN, NULL);
-  if (! driver->initialized)
+  if (device == Mnil)
+    {
+#ifdef HAVE_FREETYPE
+      interface = &null_interface;
+      if (! interface->handle)
+       {
+         (*interface->init) ();
+         interface->handle = (void *) 1;
+       }
+#else  /* not HAVE_FREETYPE */
+      MERROR (MERROR_WIN, NULL);
+#endif /* not HAVE_FREETYPE */
+    }
+  else
     {
-      if ((*driver->init) () < 0)
+      interface = mplist_get (device_library_list, device);
+      if (! interface)
        MERROR (MERROR_WIN, NULL);
-      driver->initialized = 1;
-    }      
+      if (! interface->handle)
+       {
+         if (! (interface->handle = dlopen (interface->library, RTLD_NOW))
+             || ! (interface->init = dlsym (interface->handle, "device_init"))
+             || ! (interface->open = dlsym (interface->handle, "device_open"))
+             || ! (interface->fini = dlsym (interface->handle, "device_fini"))
+             || (*interface->init) () < 0)
+           {
+             fprintf (stderr, "%s\n", (char *) dlerror ());
+             if (interface->handle)
+               dlclose (interface->handle);
+             MERROR (MERROR_WIN, NULL);
+           }
+       }
+    }
 
   M17N_OBJECT (frame, free_frame, MERROR_FRAME);
-  if ((*driver->open) (frame, plist) < 0)
+  if ((*interface->open) (frame, plist) < 0)
     {
       free (frame);
       MERROR (MERROR_WIN, NULL);
     }
-  frame->driver = driver;
 
   if (! mframe_default)
     mframe_default = frame;