diff --git fullcalendar.info fullcalendar.info
index 6d9e8c7..98d3426 100644
--- fullcalendar.info
+++ fullcalendar.info
@@ -9,5 +9,6 @@ dependencies[] = date
 
 files[] = fullcalendar_plugin_display_page.inc
 files[] = fullcalendar_handler_empty.inc
+files[] = fullcalendar_handler_field_gcal.inc
 files[] = views_plugin_node_fullcalendar.inc
 files[] = views_plugin_style_fullcalendar.inc
diff --git fullcalendar.module fullcalendar.module
index db7132a..210915c 100644
--- fullcalendar.module
+++ fullcalendar.module
@@ -183,6 +183,13 @@ function theme_fullcalendar_classname($variables) {
  * Passes options to the FullCalendar plugin as JavaScript settings.
  */
 function template_preprocess_views_view_fullcalendar(&$vars) {
+  $gcal = array();
+  foreach ($vars['view']->field as $field) {
+    if ($field->field == 'gcal') {
+      $gcal[] = $field->render(array());
+    }
+  }
+  $vars['options']['gcal'] = $gcal;
   fullcalendar_get_settings($vars['options']);
 }
 function fullcalendar_get_settings($options) {
@@ -213,6 +220,7 @@ function fullcalendar_get_settings($options) {
     'monthString' => t('Month'),
     'todayString' => t('Today'),
     'isRTL' => $language->direction,
+    'gcal' => $options['gcal'],
   );
 
   if ($options['times']['fc_default_date']) {
@@ -224,6 +232,7 @@ function fullcalendar_get_settings($options) {
   drupal_add_library('fullcalendar', 'fullcalendar');
   drupal_add_js(array('fullcalendar' => $settings), 'setting');
   drupal_add_js(drupal_get_path('module', 'fullcalendar') . '/fullcalendar.views.js');
+  drupal_add_js(drupal_get_path('module', 'fullcalendar') . '/gcal.js');
 }
 
 /**
diff --git fullcalendar.views.inc fullcalendar.views.inc
index 93495a1..d071197 100644
--- fullcalendar.views.inc
+++ fullcalendar.views.inc
@@ -83,6 +83,13 @@ function fullcalendar_views_data() {
         'handler' => 'fullcalendar_handler_empty',
       ),
     ),
+    'gcal' => array(
+      'title' => t('Google Calendar'),
+      'help' => t('Display events from a Google Calendar.'),
+      'field' => array(
+        'handler' => 'fullcalendar_handler_field_gcal',
+      ),
+    ),
   );
 
   return $data;
diff --git fullcalendar.views.js fullcalendar.views.js
index cd03b15..268a7dc 100644
--- fullcalendar.views.js
+++ fullcalendar.views.js
@@ -58,7 +58,8 @@ attach: function(context) {
       week: Drupal.settings.fullcalendar.weekString,
       month: Drupal.settings.fullcalendar.monthString
     },
-    events: function(start, end, callback) {
+    eventSources: [
+    function(start, end, callback) {
       var events = [];
 
       $('.fullcalendar_event').each(function() {
@@ -81,6 +82,8 @@ attach: function(context) {
 
       callback(events);
     },
+    $.fullCalendar.gcalFeedArray(Drupal.settings.fullcalendar.gcal)
+    ],
     eventDrop: function(event, dayDelta, minuteDelta, allDay, revertFunc) {
       $.post(Drupal.settings.basePath + 'fullcalendar/ajax/update/drop/'+ event.eid,
         'field=' + event.field + '&entity_type=' + event.entity_type + '&index=' + event.index + '&day_delta=' + dayDelta + '&minute_delta=' + minuteDelta + '&all_day=' + allDay,
diff --git fullcalendar_handler_field_gcal.inc fullcalendar_handler_field_gcal.inc
new file mode 100644
index 0000000..2d7eadc
--- /dev/null
+++ fullcalendar_handler_field_gcal.inc
@@ -0,0 +1,66 @@
+<?php
+// $Id$
+
+/**
+ * A handler to provide a field that attaches a Google Calendar feed.
+ */
+class fullcalendar_handler_field_gcal extends views_handler_field {
+  function query() {
+    // do nothing -- to override the parent query.
+  }
+
+  function allow_advanced_render() {
+    return FALSE;
+  }
+
+  function option_definition() {
+    $options['label'] = array('default' => $this->definition['title'], 'translatable' => TRUE);
+    $options['gcal'] = array('default' => '');
+    $options['class'] = array('default' => 'fc-event-default fc-event-gcal');
+    $options['timezone'] = array('default' => date_default_timezone_get());
+    $options['editable'] = array('default' => FALSE);
+    return $options;
+  }
+
+  function options_form(&$form, &$form_state) {
+    $form['label'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Label'),
+      '#default_value' => isset($this->options['label']) ? $this->options['label'] : '',
+      '#description' => t('The label for this field that will be displayed to end users if the style requires it.'),
+    );
+    $form['gcal'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Feed URL'),
+      '#default_value' => $this->options['gcal'],
+    );
+    $form['class'] = array(
+      '#type' => 'textfield',
+      '#title' => t('CSS Class'),
+      '#default_value' => $this->options['class'],
+    );
+    $form['timezone'] = array(
+      '#type' => 'select',
+      '#title' => t('Time zone'),
+      '#default_value' => $this->options['timezone'],
+      '#options' => system_time_zones(),
+      '#attributes' => array('class' => array('timezone-detect')),
+    );
+    $form['editable'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Allow editing of events'),
+      '#default_value' => $this->options['editable'],
+    );
+  }
+
+  function render($values) {
+    return array(
+      $this->options['gcal'],
+      array(
+        'editable' => $this->options['editable'],
+        'className' => $this->options['class'],
+        'currentTimezone' => $this->options['timezone'],
+      ),
+    );
+  }
+}
diff --git gcal.js gcal.js
new file mode 100644
index 0000000..099a39b
--- /dev/null
+++ gcal.js
@@ -0,0 +1,83 @@
+/*
+ * FullCalendar v1.4.10 Google Calendar Extension
+ *
+ * Copyright (c) 2010 Adam Shaw
+ * Dual licensed under the MIT and GPL licenses, located in
+ * MIT-LICENSE.txt and GPL-LICENSE.txt respectively.
+ *
+ * Date: Sat Jan 1 23:46:27 2011 -0800
+ *
+ */
+
+(function($) {
+	$.fullCalendar.gcalFeedArray = function(feedArray) {
+
+		return function(start, end, callback) {
+			var events = [];
+			var nrFeedsCollected = 0;
+
+			if (feedArray.length == 0) {
+				callback(events);
+			}
+
+			for (i=0; i<feedArray.length; i++) {
+				feedUrl = feedArray[i][0];
+				feedUrl = feedUrl.replace(/\/basic$/, '/full');
+				options = feedArray[i][1] || {};
+
+				var params = {
+					'start-min': $.fullCalendar.formatDate(start, 'u'),
+					'start-max': $.fullCalendar.formatDate(end, 'u'),
+					'singleevents': true,
+					'events' : events,
+					'max-results': 9999
+				};
+				var ctz = options.currentTimezone;
+				if (ctz) {
+					params.ctz = ctz = ctz.replace(' ', '_');
+				}
+				$.getJSON(feedUrl + "?alt=json-in-script&callback=?", params, function(data) {
+					if (data.feed.entry) {
+						$.each(data.feed.entry, function(i, entry) {
+							var startStr = entry['gd$when'][0]['startTime'],
+							start = $.fullCalendar.parseISO8601(startStr, true),
+							end = $.fullCalendar.parseISO8601(entry['gd$when'][0]['endTime'], true),
+							allDay = startStr.indexOf('T') == -1,
+							url;
+							$.each(entry.link, function() {
+								if (this.type == 'text/html') {
+									url = this.href;
+									if (ctz) {
+										url += (url.indexOf('?') == -1 ? '?' : '&') + 'ctz=' + ctz;
+									}
+								}
+							});
+							if (allDay) {
+								$.fullCalendar.addDays(end, -1); // make inclusive
+							}
+							events.push({
+								id: entry['gCal$uid']['value'],
+								title: entry['title']['$t'],
+								url: url,
+								start: start,
+								end: end,
+								allDay: allDay,
+								location: entry['gd$where'][0]['valueString'],
+								description: entry['content']['$t'],
+								className: options.className,
+								editable: options.editable || false
+							});
+						});
+					}
+
+					nrFeedsCollected++;
+					if (nrFeedsCollected === feedArray.length) {
+						callback(events);
+					}
+				});
+			}
+
+		}
+	}
+
+})(jQuery);
