Index: skinr.api.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/skinr/skinr.api.php,v
retrieving revision 1.1
diff -u -p -r1.1 skinr.api.php
--- skinr.api.php	17 Dec 2010 22:15:24 -0000	1.1
+++ skinr.api.php	4 Jan 2011 21:00:23 -0000
@@ -93,15 +93,19 @@ function hook_skinr_config() {
 }
 
 /**
- * Register Skinr API information. This is required for your module to have
- * its include files loaded.
+ * Register a Skinr plugin.
  *
- * The full documentation for this hook is in the advanced help.
+ * @return
+ *   An array of information to assist in the inclusion of Skinr plugins, if
+ *   necessary. Optional elements are:
+ *   - 'directory': Optional sub-directory of the plugin containing further
+ *   plugin files.
+ *   - 'type': Optional plugin type, can be 'module' or 'skin', defaults to
+ *   'skin'.
  */
-function hook_skinr_api() {
+function hook_skinr_api_2() {
   return array(
-    'api' => 1,
-    'path' => drupal_get_path('module', 'modulename'),
+    'directory' => 'skins',
   );
 }
 
Index: skinr.handlers.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/skinr/skinr.handlers.inc,v
retrieving revision 1.9
diff -u -p -r1.9 skinr.handlers.inc
--- skinr.handlers.inc	20 Dec 2010 21:42:29 -0000	1.9
+++ skinr.handlers.inc	4 Jan 2011 21:00:23 -0000
@@ -143,23 +143,23 @@ function skinr_submit_handler(&$form, $f
 // Declare API compatibility on behalf of core modules:
 
 /**
- * Implements hook_skinr_api().
- *
- * This one is used as the base to reduce errors when updating.
+ * Implements hook_skinr_api_VERSION().
  */
-function skinr_skinr_api() {
+function skinr_skinr_api_2() {
+  // Skinr defines module plugins on behalf of core and popular contrib modules.
+  // These plugins are stored under the 'modules' directory so it is set here.
   return array(
-    'api' => 1,
-    'path' => drupal_get_path('module', 'skinr') . '/modules',
+    'directory' => 'modules',
+    'type' => 'module',
   );
 }
 
-function block_skinr_api() { return skinr_skinr_api(); }
+function block_skinr_api_2() { return skinr_skinr_api_2(); }
 
-function comment_skinr_api() { return skinr_skinr_api(); }
+function comment_skinr_api_2() { return skinr_skinr_api_2(); }
 
-function node_skinr_api() { return skinr_skinr_api(); }
+function node_skinr_api_2() { return skinr_skinr_api_2(); }
 
-function panels_skinr_api() { return skinr_skinr_api(); }
+function panels_skinr_api_2() { return skinr_skinr_api_2(); }
 
-function views_skinr_api() { return skinr_skinr_api(); }
+function views_skinr_api_2() { return skinr_skinr_api_2(); }
Index: skinr.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/skinr/skinr.module,v
retrieving revision 1.37
diff -u -p -r1.37 skinr.module
--- skinr.module	20 Dec 2010 21:42:29 -0000	1.37
+++ skinr.module	4 Jan 2011 21:00:23 -0000
@@ -39,7 +39,8 @@ function skinr_module_implements_alter(&
  */
 function skinr_init() {
   module_load_include('inc', 'skinr', 'skinr.handlers');
-  skinr_module_load_all_includes();
+  // Load module and skin plugins.
+  skinr_get_plugins();
 }
 
 /**
@@ -421,38 +422,119 @@ function skinr_rule_visible($rid) {
 // Include file helpers.
 
 /**
- * Includes $module.skinr.inc files.
+ * Load include files for Skinr plugins implemented by modules and themes.
+ *
+ * @return
+ *   An array of plugins keyed by hook name. Plugins contain the following keys:
+ *   - 'type': Plugin type, 'module' or 'skin'.
+ *   - 'plugin': The name of the owning module or theme of this plugin, usually
+ *     the same as the name of the plugin.
+ *   - 'name': The name of the plugin.
+ *   - 'filename': The filename of the skin plugin.
+ *   - 'path': This plugin's path.
+ *
+ * @see skinr_get_directories()
  */
-function skinr_module_load_all_includes() {
-  foreach (skinr_get_module_apis() as $module => $info) {
-    $file = DRUPAL_ROOT . "/$info[path]/$module.skinr.inc";
-    if (is_file($file)) {
-      require_once $file;
+function skinr_get_plugins() {
+  // Store hooks statically because the files can't be reincluded, so there's
+  // no use in being able to clear it.
+  $plugins = &drupal_static(__FUNCTION__);
+
+  if (empty($plugins)) {
+    $plugins = array();
+
+    // Get a list of plugin directories..
+    $directories = skinr_get_directories();
+    foreach ($directories as $plugin_type => $source_directory) {
+      // Get Skinr plugin files.
+      $file_list = array();
+      foreach ($source_directory as $plugin => $path) {
+        $file_list[$plugin] = drupal_system_listing("/\.skinr\.inc\$/", $path, 'name', 0);
+      }
+
+      // Load plugins.
+      foreach ($file_list as $plugin => $files) {
+        foreach ($files as $file) {
+          // Hold on to the file prefix name, it may differ from the plugin name.
+          $name = substr($file->name, 0, strpos($file->name, '.'));
+          // Be sure the plugin is included.
+          include_once './' . $file->uri;
+          $plugins[$plugin_type][$plugin][$name] = array(
+            'type' => $plugin_type,
+            'plugin' => $plugin,
+            'name' => $name,
+            'filename' => $file->name,
+            'path' => dirname($file->uri),
+          );
+        }
+      }
     }
   }
+  return $plugins;
 }
 
 /**
- * Get a list of modules that support skinr.
+ * Return a list of directories for Skinr plugins.
+ *
+ * @return
+ *   An array containing plugins indexed by the plugin type, 'module' or 'skin'.
+ *
+ * @see skinr_get_plugins()
  */
-function skinr_get_module_apis() {
-  $cache = &drupal_static(__FUNCTION__);
+function skinr_get_directories() {
+  $directories = array();
 
-  if (!isset($cache)) {
-    $cache = array();
-    foreach (module_implements('skinr_api') as $module) {
-      $function = $module . '_skinr_api';
-      $info = $function();
-      if (isset($info['api']) && $info['api'] == 1.000) {
-        if (!isset($info['path'])) {
-          $info['path'] = drupal_get_path('module', $module);
+  // Load directories for modules.
+  foreach (module_implements('skinr_api_2') as $module) {
+    // Load the path where these plugins can be found.
+    $info = module_invoke($module, 'skinr_api_2');
+    $directory = '';
+    if (isset($info) && isset($info['directory'])) {
+      $directory = '/' . $info['directory'];
+    }
+    // Modules can implement Skinr plugins of type 'module' or 'skin'. Module
+    // plugins should be explicit of their integration type.
+    $type = isset($info['type']) ? $info['type'] : 'skin';
+    $directories[$type][$module] = drupal_get_path('module', $module) . $directory;
+  }
+
+  // Load directories for themes.
+  foreach (list_themes() as $theme) {
+    if (!empty($theme->status)) {
+      // Discover Skinr plugin files under the active theme.
+      $path = drupal_get_path('theme', $theme->name);
+      $file_list = drupal_system_listing("/\.skinr\.inc\$/", $path, 'name', 0);
+      if (!empty($file_list)) {
+        // Include skin plugin files.
+        foreach ($file_list as $file) {
+          include_once './' . $file->uri;
+        }
+        // Check for API compatibility.
+        $function = $theme->name . '_skinr_api_2';
+        if (function_exists($function)) {
+          $info = $function();
+          // Check for skin sub-directories defined by the API implementation.
+          if (isset($info) && isset($info['directory'])) {
+            $path .= '/' . $info['directory'];
+          }
+          // Themes can only define skin plugins so include this theme.
+          $directories['skin'][$theme->name] = $path;
         }
-        $cache[$module] = $info;
       }
     }
   }
 
-  return $cache;
+  return $directories;
+}
+
+/**
+ * Implements hook_hook_info().
+ */
+function skinr_hook_info() {
+  $hooks['skinr_api_2'] = array(
+    'group' => 'skinr',
+  );
+  return $hooks;
 }
 
 // -----------------------------------------------------------------------
@@ -758,24 +840,6 @@ function skinr_skin_info_status_default(
 }
 
 /**
- * Get a list of plugin hooks.
- *
- * @return
- *   An array of hook details keyed by hook name. The hook details contain the
- *   following keys:
- *   - 'type': Available options are 'module' or 'theme'.
- *   - 'name': The name of the owner module or theme of this plugin.
- *   - 'plugin': The name of the skins plugin.
- *   - 'path': This plugin's path.
- */
-function skinr_plugin_hooks() {
-  // @todo Load the include files and get an array of hooks; we need to
-  //   know which module and which plugin comprises the hook.
-  $hooks = array();
-  return $hooks;
-}
-
-/**
  * Helper function to prepend a path to an array of stylesheet or script filenames.
  *
  * If the url is absolute (e.g. the url start with 'http://' or 'https://')
@@ -812,14 +876,15 @@ function _skinr_add_path_to_files(&$file
  *
  * @param $skin_infos
  *   A skins array as returned from a skins plugin.
- * @param $source
+ * @param $plugin
  *   An array with the following keys:
- *   - 'type': Available options are 'module' or 'theme'.
- *   - 'name': The name of the owner module or theme of this plugin.
- *   - 'plugin': The name of the skins plugin.
- *   - 'path': This plugin's path.
+ *   - 'type': Plugin type, 'module' or 'skin'.
+ *   - 'plugin': The name of the owner module or theme of this plugin.
+ *   - 'name': The name of the plugin.
+ *   - 'filename': The filename of the skin plugin.
+ *   - 'path': Plugin path.
  */
-function skinr_skin_info_process(&$skin_infos, $source) {
+function skinr_skin_info_process(&$skin_infos, $plugin) {
   foreach ($skin_infos as $skin_name => $skin_info) {
     // Merge in defaults.
     $skin_infos[$skin_name] = array_merge(skinr_skin_info_default(), $skin_infos[$skin_name]);
@@ -828,7 +893,7 @@ function skinr_skin_info_process(&$skin_
     $skin_infos[$skin_name]['name'] = $skin_name;
 
     // Merge in source information.
-    $skin_infos[$skin_name]['source'] = $source;
+    $skin_infos[$skin_name]['plugin'] = $plugin;
 
     // Merge in default statuses for all themes.
     $skin_infos[$skin_name]['status'] = array_merge(skinr_skin_info_status_default($skin_infos[$skin_name]['default_status']), $skin_infos[$skin_name]['status']);
@@ -880,20 +945,27 @@ function skinr_get_skin_info() {
     // are found.
     $skin_infos = array();
 
-    // Load skins from hook_skinr_skins().
-    $hooks = skinr_plugin_hooks();
-    foreach ($hooks as $hook => $source) {
-      $function = $hook . '_skinr_skin_info';
-      $result = $function();
-      if (isset($result)) {
-        if (!is_array($result)) {
-          $result = array($result);
+    // Load skins from skin plugins.
+    $plugins = skinr_get_plugins();
+    if (!empty($plugins['skin'])) {
+      $plugins = $plugins['skin'];
+      foreach ($plugins as $name => $skins) {
+        foreach ($skins as $skin_name => $skin) {
+          // Retrieve skin definitions.
+          $function = $skin_name . '_skinr_skin_info';
+          if (function_exists($function)) {
+            $result = $function();
+            if (isset($result)) {
+              if (!is_array($result)) {
+                $result = array($result);
+              }
+    
+              // Make any programatic changes.
+              skinr_skin_info_process($result, $skin);
+              $skin_infos = array_merge_recursive($skin_infos, $result);
+            }
+          }
         }
-
-        // Make any programatic changes.
-        skinr_skin_info_process($result, $source);
-
-        $skin_infos = array_merge_recursive($skin_infos, $result);
       }
     }
 
@@ -919,22 +991,29 @@ function skinr_get_group_info() {
     $group_infos = array();
 
     // Load skins from hook_skinr_groups().
-    $hooks = skinr_plugin_hooks();
-    foreach ($hooks as $hook => $source) {
-      $function = $hook . '_skinr_group_info';
-      $result = $function();
-      if (isset($result)) {
-        if (!is_array($result)) {
-          $result = array($result);
-        }
-
-        // Make any programatic changes.
-        // Merge in defaults.
-        foreach ($result as $group_name => $group_info) {
-          $result[$group_name] = array_merge(skinr_group_info_default(), $group_info);
+    $plugins = skinr_get_plugins();
+    $plugins = $plugins['skin'];
+    if (!empty($plugins['skin'])) {
+      foreach ($plugins as $name => $skins) {
+        foreach ($skins as $skin_name => $skin) {
+          $function = $skin_name . '_skinr_group_info';
+          if (function_exists($function)) {
+            $result = $function();
+            if (isset($result)) {
+              if (!is_array($result)) {
+                $result = array($result);
+              }
+    
+              // Make any programatic changes.
+              // Merge in defaults.
+              foreach ($result as $group_name => $group_info) {
+                $result[$group_name] = array_merge(skinr_group_info_default(), $group_info);
+              }
+    
+              $group_infos = array_merge_recursive($group_infos, $result);
+            }
+          }
         }
-
-        $group_infos = array_merge_recursive($group_infos, $result);
       }
     }
 
