Index: skinr.module
===================================================================
--- skinr.module	(revision 5200)
+++ skinr.module	(working copy)
@@ -405,6 +405,123 @@
   return $cache;
 }
 
+/**
+ * Get a list of filenames and location for skins.
+ */
+function skinr_load_all_info_paths($reset = FALSE) {
+  static $info = array();
+
+  if ($reset) {
+    $info = array();
+  }
+
+  if (empty($info)) {
+    // Find skins in skins folders.
+    $mask = '\.skinr$';
+    $directory = 'skins';
+    $files = drupal_system_listing($mask, $directory);
+
+    // Find skins in theme folders.
+    $mask = '\.skinr$';
+    $directory = 'themes';
+    $files = $files = array_merge($files, drupal_system_listing($mask, $directory));
+
+    // Find skins in module folders.
+    $mask = '\.skinr$';
+    $directory = 'modules';
+    $files = $files = array_merge($files, drupal_system_listing($mask, $directory));
+
+    /*
+    // If our filename contains multiple dots in the extension, for example
+    // filename.skinr.inc, we need to fix the name and key.
+    foreach ($files as $skinset) {
+      $key = substr($skinset->name, 0, -5);
+      $skinset->name = $key;
+      $info[$key] = $skinset;
+    }
+    */
+    $info = $files;
+  }
+
+  return $info;
+}
+
+/**
+ * Load all skins.
+ */
+function skinr_load_all_info() {
+  $info = skinr_load_all_info_paths();
+
+  $return = array();  
+  foreach ($info as $skinset) {
+    $result = skinr_load_info($skinset->name, $skinset);
+    if (isset($result) && is_array($result)) {
+      $return = array_merge_recursive($return, $result);
+    }
+    elseif (isset($result)) {
+      $return[$skinset->name] = $result;
+    }
+  }
+
+  return $return;
+}
+
+/**
+ * Load a skin.
+ */
+function skinr_load_info($skin, $skinset = NULL) {
+  if (is_null($skinset)) {
+    $info = skinr_load_all_info_paths();
+    if (!empty($info[$skin])) {
+      $skinset = $info[$skin];
+    }
+    else {
+      return FALSE;
+    }
+  }
+
+  if (is_file($skinset->filename)) {
+    require_once $skinset->filename;
+
+    $function = $skinset->name .'_skinr_info';
+    $skinset->info = call_user_func_array($function, array());
+    if (!isset($skinset->info)) {
+      return FALSE; 
+    }
+    if (!is_array($skinset->info)) {
+      $skinset->info = array($skinset->info);
+    }
+
+    foreach ($skinset->info as $key => $info) {
+      $skinset->info[$key] += skinr_skins_default();
+
+      // Give the screenshot proper path information.
+      if (!empty($skinset->info[$key]['screenshot'])) {
+        $skinset->info[$key]['screenshot'] = dirname($skinset->filename) .'/'. $skinset->info[$key]['screenshot'];
+      }
+
+      // Give all css and js files proper path information.
+      _skinr_add_paths_to_files($skinset->info[$key]['skinr'], dirname($skinset->filename));
+
+      // Invoke hook_skinr_info_alter() to give installed modules a chance to
+      // modify the data in the .skin.inc files if necessary.
+      drupal_alter('skinr_info', $skinset->info[$key], $skinset);
+
+      // @todo In the future we might want to disable the below code to allow
+      //       multiple skinsets in a single file. This would require
+      //       substantial re-writing of certain pieces of code.
+      $skinset->info = $skinset->info[$key];
+      break;
+      //       End code to remove.
+    }
+
+    return $skinset;
+  }
+  else {
+    return FALSE;
+  }
+}
+
 // -----------------------------------------------------------------------
 // Skinr data handling functions.
 
@@ -627,77 +744,9 @@
 }
 
 /**
- * Retrieves all the Skinr skins from theme parents. Theme skins
- * will override any skins of the same name from its parents.
- */
-function skinr_inherited_skins($theme) {
-  $themes = _system_theme_data();
-
-  $all_skins = $skins = array();
-  $base_theme = (!empty($themes[$theme]->info['base theme'])) ? $themes[$theme]->info['base theme'] : '';
-  while ($base_theme) {
-    // Add in path info here.
-    $base_skins = (!empty($themes[$base_theme]->info['skinr'])) ? (array)$themes[$base_theme]->info['skinr'] : array();
-    $base_path  = $path_root = dirname($themes[$base_theme]->filename);
-    _skinr_add_paths_to_files($base_skins, $base_path);
-
-    $all_skins[] = $base_skins;
-    $base_theme = (!empty($themes[$base_theme]->info['base theme'])) ? $themes[$base_theme]->info['base theme'] : '';
-  }
-  array_reverse($all_skins);
-  foreach ($all_skins as $new_skin) {
-    $skins = array_merge($skins, $new_skin);
-  }
-  return $skins;
-}
-
-/**
- * Helper function to scan and collect skin .info data.
+ * Helper function to process a .skinr file.
  *
  * @return
- *   An associative array of skins information.
- */
-function _skinr_skins_data() {
-  static $skins_info = array();
-
-  if (empty($skins_info)) {
-    // Find skins.
-    $mask = '\.info$';
-    $directory = 'skins';
-    $skinsets = drupal_system_listing($mask, $directory);
-
-    // Find skins in theme folders.
-    $themes = _system_theme_data();
-    foreach ($themes as $theme) {
-      $dir = dirname($theme->filename) .'/'. $directory;
-      $skinsets = array_merge($skinsets, file_scan_directory($dir, $mask, array('.', '..', 'CVS'), 0, TRUE, 'name', 1));
-    }
-
-    $defaults = skinr_skins_default();
-
-    foreach ($skinsets as $key => $skinset) {
-      $skinsets[$key]->info = drupal_parse_info_file($skinset->filename) + $defaults;
-
-      // Give the screenshot proper path information.
-      if (!empty($skinsets[$key]->info['screenshot'])) {
-        $skinsets[$key]->info['screenshot'] = dirname($skinsets[$key]->filename) .'/'. $skinsets[$key]->info['screenshot'];
-      }
-
-      // Invoke hook_skinr_info_alter() to give installed modules a chance to
-      // modify the data in the .info files if necessary.
-      drupal_alter('skinr_info', $skinsets[$key]->info, $skinsets[$key]);
-    }
-
-    $skins_info = $skinsets;
-  }
-
-  return $skins_info;
-}
-
-/**
- * Helper function to process a skin or theme .info file.
- *
- * @return
  *    A skinset.
  */
 function _skinr_skinset($info) {
@@ -706,6 +755,7 @@
     'skins' => array(),
   );
 
+  // @todo Account for $info->info being an array.
   if (!empty($info->info['skinr'])) {
     $path_root = dirname($info->filename);
 
@@ -729,17 +779,6 @@
       }
     }
 
-    // Add paths to $skinr_info.
-    _skinr_add_paths_to_files($skinr_info, $path_root);
-
-    // Inherit skins from parent theme, if inherit_skins is set to true.
-    if (!empty($skinset['options']['inherit_skins'])) {
-      // Paths get automatically added to base theme info.
-      $base_info  = skinr_inherited_skins($info->name);
-      // Merge base theme and current.
-      $skinr_info = array_merge($base_info, $skinr_info);
-    }
-
     $defaults = skinr_skin_default();
 
     foreach ($skinr_info as $id => $skin) {
@@ -794,7 +833,7 @@
 }
 
 /**
- * Helper function to prepend a path to an array of stylesheets or scripts in a .info file.
+ * Helper function to prepend a path to an array of stylesheets or scripts in a .skinr file.
  *
  * @param $files
  *   A an array of filenames that need the path prepended.
@@ -829,56 +868,67 @@
 }
 
 /**
- * Helper function to process an array of skins or themes .info files.
+ * Helper function to process an array of skins or themes .skinr files.
  *
- * @param $type
- *   Either 'theme' or 'skinset'.
  * @param $refresh
  *   Whether to reload the list of skinsets from the database or not.
  *
  * @return
  *    An array of skinsets.
  */
-function skinr_skinsets($type, $refresh = FALSE) {
-  static $skinsets = array('theme' => array(), 'skinset' => array());
+function skinr_skinsets($refresh = FALSE) {
+  static $skinsets = array();
 
   if ($refresh) {
-    $skinsets[$type] = array();
+    $skinsets = array();
   }
 
-  if (empty($skinsets[$type])) {
+  if (empty($skinsets)) {
     $themes = _system_theme_data();
 
-    if ($type == 'theme') {
-      foreach ($themes as $theme) {
-        $skinset = new StdClass();
-        $skinset->filename = $theme->filename;
-        $skinset->name = $theme->name;
-        $skinset->status = $theme->status ? 1 : 0;
-        $skinset->info = $theme->info;
+    $result = db_query("SELECT * FROM {skinr_skinsets}");
+    while ($skinset = db_fetch_object($result)) {
+      if (file_exists($skinset->filename)) {
+        $skinset->info = unserialize($skinset->info);
 
-        $skinsets[$type][$skinset->name] = $skinset;
+        $skinsets[$skinset->name] = $skinset;
       }
     }
-    elseif ($type == 'skinset') {
-      $result = db_query("SELECT * FROM {skinr_skinsets}");
-      while ($skinset = db_fetch_object($result)) {
-        if (file_exists($skinset->filename)) {
-          $skinset->info = unserialize($skinset->info);
 
-          $skinsets[$type][$skinset->name] = $skinset;
-        }
-      }
-    }
-
     $default_status = array();
     foreach ($themes as $theme) {
       $default_status[$theme->name] = $theme->name;
     }
 
-    foreach ($skinsets[$type] as $key => $skinset) {
-      $skinset->type = $type;
+    foreach ($skinsets as $key => $skinset) {
+      if (isset($themes[$key])) {
+        $skinset->type = 'theme';
+        $skinset->status = !empty($theme->status) ? 1 : 0;
+      }
+      else {
+        $skinset->type = 'skinset';
+      }
 
+      // Inherit skins from base theme, if inherit_skins is set to true.
+      // @todo Account for $skinset->info being an array.
+      if (!empty($skinset->info['skinr']['options']['inherit_skins'])) {
+        // Merge base theme and current.
+        $inheriting = TRUE;
+        $merged_skins = array();
+        $current_skinset = $skinset;
+        while ($inheriting) {
+          $inheriting = FALSE;
+          if (!empty($current_skinset->info['base theme'])) {
+            if (!empty($skinsets[$current_skinset->info['base theme']])) {
+              $current_skinset = $skinsets[$current_skinset->info['base theme']];
+              $merged_skins = array_merge($current_skinset->info['skinr'], $merged_skins);
+              $inheriting = TRUE;
+            }
+          }
+        }
+        $skinset->info['skinr'] = array_merge($merged_skins, $skinset->info['skinr']);
+      }
+
       $additional = _skinr_skinset($skinset);
       $skinset->options = $additional['options'];
       $skinset->skins = $additional['skins'];
@@ -890,7 +940,7 @@
     }
   }
 
-  return $skinsets[$type];
+  return $skinsets;
 }
 
 /**
@@ -928,9 +978,20 @@
  *   Array of all available skinsets and their data.
  */
 function skinr_rebuild_skinset_data() {
-  $skinsets = _skinr_skins_data();
+  $skinsets = skinr_load_all_info();
   skinr_get_files_database($skinsets);
 
+  $themes = list_themes();
+  foreach ($skinsets as $key => $skinset) {
+    if (isset($themes[$key])) {
+      $skinset->status = !empty($themes[$key]->status) ? 1 : 0;
+      $skinset->type = 'theme';
+    }
+    else {
+      $skinset->type = 'skinset';
+    }
+  }
+
   db_query("DELETE FROM {skinr_skinsets}");
 
   foreach ($skinsets as $skinset) {
@@ -981,20 +1042,21 @@
   static $cache = NULL;
 
   if (is_null($cache)) {
-    $skins_skinsets  = skinr_skinsets('skinset');
-    $themes_skinsets = skinr_skinsets('theme');
+    $skinsets = skinr_skinsets();
 
     // Need to merge all skins skinsets into a single list of skins.
     // Also merge in the groups information.
     $additional_skins = array();
     $groups = array();
-    foreach ($skins_skinsets as $key => $skinset) {
-      if (!empty($skinset->skins) && $skinset->status == 1) {
-        $additional_skins += $skinset->skins;
+    foreach ($skinsets as $key => $skinset) {
+      if ($skinset->type == 'skinset') {
+        if (!empty($skinset->skins) && $skinset->status == 1) {
+          $additional_skins += $skinset->skins;
+        }
+        if (!empty($skinset->options['groups'])) {
+          $groups += $skinset->options['groups'];
+        }
       }
-      if (!empty($skinset->options['groups'])) {
-        $groups += $skinset->options['groups'];
-      }
     }
 
     // Merge the additional skins into each theme, even if that theme has no
@@ -1005,16 +1067,18 @@
         continue;
       }
 
-      if (isset($themes_skinsets[$theme->name])) {
-        $cache[$theme->name] = $themes_skinsets[$theme->name];
+      if (!empty($skinsets[$theme->name])) {
+        $cache[$theme->name] = $skinsets[$theme->name];
         $cache[$theme->name]->skins += $additional_skins;
         $cache[$theme->name]->options['groups'] += $groups;
       }
       else {
-        $cache[$theme->name] = array(
-          'options' => array('groups' => $groups),
-          'skins' => $additional_skins,
-        );
+        $cache[$theme->name] = new StdClass();
+        $cache[$theme->name]->name = $theme->name;
+        $cache[$theme->name]->status = 1;
+        $cache[$theme->name]->type = 'theme';
+        $cache[$theme->name]->skins = $additional_skins;
+        $cache[$theme->name]->options = array('groups' => $groups);
       }
     }
   }
Index: skinr_ui.admin.inc
===================================================================
--- skinr_ui.admin.inc	(revision 5200)
+++ skinr_ui.admin.inc	(working copy)
@@ -286,7 +286,7 @@
   }
 
   $output .= '<li><dl class="multiselect">';
-  
+
   $element_children = element_children($form['filter']);
   if (!empty($element_children)) {
     $output .= (!empty($form['current']) ? '<dt><em>'. t('and') .'</em> '. t('where') .'</dt>' : '') .'<dd class="a">';
@@ -294,10 +294,10 @@
       $output .= drupal_render($form['filter'][$key]);
     }
     $output .= '</dd>';
-  
+
     $output .= '<dt>'. t('is') .'</dt>';
   }
-  
+
   $output .= '<dd class="b">';
 
   foreach (element_children($form['status']) as $key) {
@@ -400,8 +400,12 @@
   // Store module list for use in the theme function.
   $form['skinsets'] = array('#type' => 'value', '#value' => $skinsets);
 
+  // Create storage for disabled skinsets as browser will disable checkboxes.
+  $form['disabled_skinsets'] = array('#type' => 'value', '#value' => array());
+
   $options = array();
   $status = array();
+  $disabled_skinsets = array();
   $incompatible_core = array();
   $incompatible_php = array();
 
@@ -434,6 +438,11 @@
       }
     }
 
+    if ($skinset->type == 'theme') {
+      $disabled_skinsets[] = $skinset->name;
+      $form['disabled_skinsets']['#value'][$skinset->name] = TRUE;
+    }
+
     $form[$skinset->name]['operations'] = array(
       '#value' => l('configure', 'admin/build/skinr/skins/settings/'. $skinset->name),
     );
@@ -443,6 +452,7 @@
     '#type' => 'checkboxes',
     '#options' => $options,
     '#default_value' => $status,
+    '#disabled_skinsets' => drupal_map_assoc($disabled_skinsets),
     '#incompatible_skinsets_core' => drupal_map_assoc($incompatible_core),
     '#incompatible_skinsets_php' => $incompatible_php,
   );
@@ -458,6 +468,24 @@
 }
 
 /**
+ * Form process callback function to disable check boxes.
+ *
+ * @param $form
+ *   The form structure.
+ * @param $edit
+ *   Not used.
+ * @ingroup forms
+ * @return
+ *   The form structure.
+ */
+function skinr_ui_skinsets_disable($form, $edit) {
+  foreach ($form['#disabled_skinsets'] as $key) {
+    $form[$key]['#attributes']['disabled'] = 'disabled';
+  }
+  return $form;
+}
+
+/**
  * Menu callback; displays a listing of all skins in a skinsets, allowing you
  * to enable or disable them individually for each theme.
  *
@@ -469,12 +497,13 @@
     '#tree' => TRUE,
   );
 
-  $skinsets = skinr_skinsets('skinset');
+  $skinsets = skinr_skinsets();
   if (!empty($skinsets[$skinset_name])) {
     $skinset = $skinsets[$skinset_name];
   }
 
   $themes = list_themes();
+  $use_themes = array();
   ksort($themes);
 
   foreach ($skinset->skins as $skin_name => $skin) {
@@ -486,10 +515,11 @@
     $status = array();
     $options = array();
     foreach ($themes as $theme) {
-      if (!$theme->status) {
+      if (!$theme->status || ($skinset->type == 'theme' && $skinset->name != $theme->name)) {
         continue;
       }
 
+      $use_themes[$theme->name] = $theme->info['name'];
       $options[$theme->name] = '';
 
       if (!empty($skin['status'][$theme->name])) {
@@ -504,6 +534,7 @@
     );
   }
 
+  $form['#themes'] = $use_themes;
   $form['skinset'] = array(
     '#type' => 'value',
     '#value' => $skinset_name,
@@ -526,7 +557,7 @@
 function skinr_ui_skinsets_form_submit($form, &$form_state) {
   // Store list of previously enabled themes and disable all themes
   $old_skinset_list = $new_skinset_list = array();
-  foreach (skinr_skinsets('skinset') as $skinset) {
+  foreach (skinr_skinsets() as $skinset) {
     if ($skinset->status) {
       $old_skinset_list[] = $skinset->name;
     }
@@ -548,7 +579,7 @@
   }
 
   // Refresh skinsets from DB.
-  skinr_skinsets('skinset', TRUE);
+  skinr_skinsets(TRUE);
 
   // @todo Disable any skins from skinsets that are now disabled.
 
@@ -837,6 +868,7 @@
  * @ingroup themeable
  */
 function theme_skinr_ui_admin_skins($form) {
+  $output = '';
   $has_skins = isset($form['rows']['#value']) && is_array($form['rows']['#value']);
   $select_header = $has_skins ? theme('table_select_header_cell') : '';
   $headers = array(
@@ -913,7 +945,10 @@
   $skinsets = $form['skinsets']['#value'];
   $packages = array();
   foreach ($skinsets as $skinset) {
-    if (!isset($skinset->info['package']) || !$skinset->info['package']) {
+    if ($skinset->type == 'theme') {
+      $skinset->info['package'] = t('Themes');
+    }
+    elseif (!isset($skinset->info['package']) || !$skinset->info['package']) {
       $skinset->info['package'] = t('Other');
     }
     $packages[$skinset->info['package']][$skinset->name] = $skinset->info;
@@ -950,6 +985,10 @@
         }
         $description .= '<div class="incompatible">'. t('This skinset requires PHP version @php_required and is incompatible with PHP version !php_version.', array('@php_required' => $php_required, '!php_version' => phpversion())) .'</div>';
       }
+      elseif (isset($form['status']['#disabled_skinsets'][$key])) {
+        $form['status'][$key]['#attributes']['disabled'] = 'disabled';
+        $status = drupal_render($form['status'][$key]);
+      }
       else {
         $status = drupal_render($form['status'][$key]);
       }
@@ -1000,11 +1039,7 @@
   $themes = list_themes();
   ksort($themes);
 
-  foreach ($themes as $theme) {
-    if (!$theme->status) {
-      continue;
-    }
-
+  foreach ($form['#themes'] as $theme_name => $theme_title) {
     $rows = array();
     foreach ($form as $key => $skin) {
       // Only look for skins.
@@ -1025,7 +1060,7 @@
       }
       $features = t('Used by: !features', array('!features' => implode(', ', $features)));
 
-      $status = drupal_render($form[$key]['status'][$theme->name]);
+      $status = drupal_render($form[$key]['status'][$theme_name]);
 
       // Style theme info
       $content = '<div class="skin-info"><h2>'. $title .'</h2><div class="description">'. $description .'</div><div class="features">'. $features .'</div></div>';
@@ -1039,14 +1074,17 @@
     }
 
     $fieldset = array(
-      '#title' => t($theme->info['name']),
+      '#title' => t($theme_title),
       '#collapsible' => TRUE,
-      '#collapsed' => $theme->name == $current_theme ? FALSE : TRUE,
+      '#collapsed' => $theme_name == $current_theme ? FALSE : TRUE,
       '#value' => theme('table', $header, $rows, array('class' => 'theme')),
     );
     $output .= theme('fieldset', $fieldset);
   }
 
+  if (empty($output)) {
+    $output .= t('This theme is disabled.');
+  }
   $output .= drupal_render($form);
   return $output;
 }
