[almanah] Create a date button in the toolbar



commit f7a2e0098ad9dca5e7e1741234af8b81cb95e4cc
Author: Ãlvaro PeÃa <alvaropg gmail com>
Date:   Sat May 26 18:58:41 2012 +0200

    Create a date button in the toolbar

 data/almanah.ui               |  259 +++++++++++++--------------
 po/POTFILES.in                |    2 +
 src/Makefile.am               |    4 +
 src/main-window.c             |   76 ++++++---
 src/widgets/calendar-button.c |  391 +++++++++++++++++++++++++++++++++++++++++
 src/widgets/calendar-button.h |   60 +++++++
 src/widgets/calendar-window.c |  165 +++++++++++++++++
 src/widgets/calendar-window.h |   59 ++++++
 8 files changed, 858 insertions(+), 158 deletions(-)
---
diff --git a/data/almanah.ui b/data/almanah.ui
index 75a82a5..fdb0a5f 100644
--- a/data/almanah.ui
+++ b/data/almanah.ui
@@ -260,10 +260,8 @@
 						<menuitem action="almanah_ui_underline"/>
 					</menu>
 				</toolitem>
-				<toolitem action="almanah_ui_jump_to_today"/>
-				<toolitem action="almanah_ui_important"/>
-				<separator/>
 				<toolitem action="almanah_ui_hyperlink"/>
+				<toolitem action="almanah_ui_important"/>
 			</toolbar>
 		</ui>
 	</object>
@@ -278,6 +276,52 @@
 		</columns>
 	</object>
 
+	<object class="AlmanahCalendarWindow" id="almanah_calendar_window">
+		<property name="border-width">12</property>
+		<property name="can-focus">True</property>
+		<property name="type">GTK_WINDOW_POPUP</property>
+		<child>
+			<object class="GtkBox" id="almanah_cw_vbox">
+				<property name="orientation">GTK_ORIENTATION_VERTICAL</property>
+				<property name="spacing">6</property>
+				<child>
+					<object class="AlmanahCalendar" id="almanah_cw_calendar">
+						<property name="width-request">200</property>
+						<property name="can-focus">True</property>
+						<property name="show-details">False</property>
+						<signal name="day-selected" handler="mw_calendar_day_selected_cb"/>
+						<child internal-child="accessible">
+							<object class="AtkObject" id="a11y-almanah_mw_calendar">
+								<property name="AtkObject::accessible-name" translatable="yes">Calendar</property>
+							</object>
+						</child>
+					</object>
+					<packing>
+						<property name="expand">True</property>
+					</packing>
+				</child>
+				<child>
+					<object class="GtkButtonBox" id="almanah_cw_button_box">
+						<property name="orientation">GTK_ORIENTATION_HORIZONTAL</property>
+						<property name="homogeneous">True</property>
+						<child>
+							<object class="GtkButton" id="almanah_cw_today_button">
+								<property name="visible">True</property>
+								<property name="can_focus">True</property>
+							</object>
+							<packing>
+								<property name="expand">False</property>
+							</packing>
+						</child>
+					</object>
+					<packing>
+						<property name="expand">False</property>
+					</packing>
+				</child>
+			</object>
+		</child>
+	</object>
+
 	<object class="AlmanahMainWindow" id="almanah_main_window">
 		<child>
 			<object class="GtkVBox" id="vbox1">
@@ -299,174 +343,115 @@
 				</child>
 				<child>
 					<object class="GtkAlignment" id="mw_alignment">
-						<property name="top-padding">6</property>
 						<child>
-							<object class="GtkHPaned" id="hpaned1">
-								<property name="can-focus">True</property>
+							<object class="GtkVBox" id="vbox3">
+								<property name="spacing">6</property>
 								<child>
-									<object class="GtkVBox" id="vbox3">
-										<property name="spacing">6</property>
-										<child>
-											<object class="GtkLabel" id="almanah_mw_date_label">
-												<property name="use-markup">True</property>
-												<attributes>
-													<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
-												</attributes>
-											</object>
-											<packing>
-												<property name="expand">False</property>
-											</packing>
-										</child>
+									<object class="GtkScrolledWindow" id="scrolledwindow1">
+										<property name="can-focus">True</property>
+										<property name="hscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
+										<property name="vscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
+										<property name="shadow-type">GTK_SHADOW_NONE</property>
 										<child>
-											<object class="GtkScrolledWindow" id="scrolledwindow1">
+											<object class="GtkTextView" id="almanah_mw_entry_view">
+												<property name="width-request">300</property>
+												<property name="height-request">300</property>
 												<property name="can-focus">True</property>
-												<property name="hscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
-												<property name="vscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
-												<property name="shadow-type">GTK_SHADOW_IN</property>
-												<child>
-													<object class="GtkTextView" id="almanah_mw_entry_view">
-														<property name="width-request">300</property>
-														<property name="height-request">300</property>
-														<property name="can-focus">True</property>
-														<property name="has-focus">True</property>
-														<property name="wrap-mode">GTK_WRAP_WORD</property>
-														<property name="left-margin">3</property>
-														<property name="right-margin">3</property>
-														<child internal-child="accessible">
-															<object class="AtkObject" id="a11y-almanah_mw_entry_view">
-																<property name="AtkObject::accessible-name" translatable="yes">Entry editing area</property>
-															</object>
-														</child>
+												<property name="has-focus">True</property>
+												<property name="wrap-mode">GTK_WRAP_WORD</property>
+												<property name="left-margin">3</property>
+												<property name="right-margin">3</property>
+												<child internal-child="accessible">
+													<object class="AtkObject" id="a11y-almanah_mw_entry_view">
+														<property name="AtkObject::accessible-name" translatable="yes">Entry editing area</property>
 													</object>
 												</child>
 											</object>
 										</child>
 									</object>
 									<packing>
-										<property name="resize">True</property>
-										<property name="shrink">False</property>
+										<property name="expand">True</property>
+										<property name="fill">True</property>
 									</packing>
 								</child>
 								<child>
-									<object class="GtkVBox" id="vbox2">
-										<property name="spacing">6</property>
-										<child>
-											<object class="GtkLabel" id="almanah_mw_calendar_label">
-												<property name="label" translatable="yes">Calendar</property>
+									<object class="GtkExpander" id="almanah_mw_events_expander">
+										<child type="label">
+											<object class="GtkLabel" id="almanah_mw_events_label">
+												<property name="label" translatable="yes">Past Events</property>
 												<accessibility>
-													<relation target="almanah_mw_calendar" type="label-for"/>
+													<relation target="almanah_mw_events_tree_view" type="label-for"/>
 												</accessibility>
 												<attributes>
 													<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
 												</attributes>
 											</object>
-											<packing>
-												<property name="expand">False</property>
-											</packing>
 										</child>
 										<child>
-											<object class="AlmanahCalendar" id="almanah_mw_calendar">
-												<property name="width-request">200</property>
+											<object class="GtkScrolledWindow" id="scrolledwindow2">
 												<property name="can-focus">True</property>
-												<property name="show-details">False</property>
-												<signal name="day-selected" handler="mw_calendar_day_selected_cb"/>
-												<accessibility>
-													<relation target="almanah_mw_calendar_label" type="labelled-by"/>
-												</accessibility>
-												<child internal-child="accessible">
-													<object class="AtkObject" id="a11y-almanah_mw_calendar">
-														<property name="AtkObject::accessible-name" translatable="yes">Calendar</property>
+												<property name="hscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
+												<property name="vscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
+												<property name="shadow-type">GTK_SHADOW_IN</property>
+												<child>
+													<object class="GtkTreeView" id="almanah_mw_events_tree_view">
+														<property name="model">almanah_mw_event_store</property>
+														<property name="can-focus">True</property>
+														<property name="headers-visible">False</property>
+														<signal name="row-activated" handler="mw_events_tree_view_row_activated_cb"/>
+														<accessibility>
+															<relation target="almanah_mw_events_label" type="labelled-by"/>
+														</accessibility>
+														<child internal-child="accessible">
+															<object class="AtkObject" id="a11y-almanah_mw_events_tree_view">
+																<property name="AtkObject::accessible-name" translatable="yes">Past Event List</property>
+															</object>
+														</child>
+														<child>
+															<object class="GtkTreeViewColumn" id="column3">
+																<child>
+																	<object class="GtkCellRendererPixbuf" id="renderer3"/>
+																	<attributes>
+																		<attribute name="icon-name">1</attribute>
+																	</attributes>
+																</child>
+															</object>
+														</child>
+														<child>
+															<object class="GtkTreeViewColumn" id="almanah_mw_event_value_column">
+																<property name="expand">True</property>
+																<child>
+																	<object class="GtkCellRendererText" id="almanah_mw_event_value_renderer"/>
+																	<attributes>
+																		<attribute name="text">3</attribute>
+																	</attributes>
+																</child>
+															</object>
+														</child>
+														<child>
+															<object class="GtkTreeViewColumn" id="almanah_mw_event_source_column">
+																<child>
+																	<object class="GtkCellRendererText" id="almanah_mw_event_source_renderer"/>
+																	<attributes>
+																		<attribute name="markup">4</attribute>
+																	</attributes>
+																</child>
+															</object>
+														</child>
 													</object>
 												</child>
 											</object>
-											<packing>
-												<property name="expand">False</property>
-											</packing>
 										</child>
 									</object>
 									<packing>
-										<property name="resize">False</property>
-										<property name="shrink">False</property>
+										<property name="fill">False</property>
+										<property name="expand">False</property>
 									</packing>
 								</child>
 							</object>
 						</child>
 					</object>
 				</child>
-				<child>
-					<object class="GtkExpander" id="almanah_mw_events_expander">
-						<child type="label">
-							<object class="GtkLabel" id="almanah_mw_events_label">
-								<property name="label" translatable="yes">Past Events</property>
-								<accessibility>
-									<relation target="almanah_mw_events_tree_view" type="label-for"/>
-								</accessibility>
-								<attributes>
-									<attribute name="weight" value="PANGO_WEIGHT_BOLD"/>
-								</attributes>
-							</object>
-						</child>
-						<child>
-							<object class="GtkScrolledWindow" id="scrolledwindow2">
-								<property name="can-focus">True</property>
-								<property name="hscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
-								<property name="vscrollbar-policy">GTK_POLICY_AUTOMATIC</property>
-								<property name="shadow-type">GTK_SHADOW_IN</property>
-								<child>
-									<object class="GtkTreeView" id="almanah_mw_events_tree_view">
-										<property name="model">almanah_mw_event_store</property>
-										<property name="can-focus">True</property>
-										<property name="headers-visible">False</property>
-										<signal name="row-activated" handler="mw_events_tree_view_row_activated_cb"/>
-										<accessibility>
-											<relation target="almanah_mw_events_label" type="labelled-by"/>
-										</accessibility>
-										<child internal-child="accessible">
-											<object class="AtkObject" id="a11y-almanah_mw_events_tree_view">
-												<property name="AtkObject::accessible-name" translatable="yes">Past Event List</property>
-											</object>
-										</child>
-										<child>
-											<object class="GtkTreeViewColumn" id="column3">
-												<child>
-													<object class="GtkCellRendererPixbuf" id="renderer3"/>
-													<attributes>
-														<attribute name="icon-name">1</attribute>
-													</attributes>
-												</child>
-											</object>
-										</child>
-										<child>
-											<object class="GtkTreeViewColumn" id="almanah_mw_event_value_column">
-												<property name="expand">True</property>
-												<child>
-													<object class="GtkCellRendererText" id="almanah_mw_event_value_renderer"/>
-													<attributes>
-														<attribute name="text">3</attribute>
-													</attributes>
-												</child>
-											</object>
-										</child>
-										<child>
-											<object class="GtkTreeViewColumn" id="almanah_mw_event_source_column">
-												<child>
-													<object class="GtkCellRendererText" id="almanah_mw_event_source_renderer"/>
-													<attributes>
-														<attribute name="markup">4</attribute>
-													</attributes>
-												</child>
-											</object>
-										</child>
-									</object>
-								</child>
-							</object>
-						</child>
-					</object>
-					<packing>
-					      <property name="fill">False</property>
-					      <property name="expand">False</property>
-					</packing>
-				</child>
 			</object>
 		</child>
 	</object>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e8d72b5..6d3db45 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -19,4 +19,6 @@ src/printing.c
 src/search-dialog.c
 src/storage-manager.c
 src/widgets/calendar.c
+src/widgets/calendar-button.c
+src/widgets/calendar-window.c
 src/uri-entry-dialog.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 425e4bd..3951d63 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -36,6 +36,10 @@ almanah_SOURCES = \
 	uri-entry-dialog.h			\
 	widgets/calendar.c			\
 	widgets/calendar.h			\
+	widgets/calendar-button.h		\
+	widgets/calendar-button.c		\
+	widgets/calendar-window.h		\
+	widgets/calendar-window.c		\
 	widgets/font-style-menu-action.h	\
 	widgets/font-style-menu-action.c	\
 	widgets/hyperlink-tag.c			\
diff --git a/src/main-window.c b/src/main-window.c
index 77617a5..a7acf59 100644
--- a/src/main-window.c
+++ b/src/main-window.c
@@ -40,6 +40,7 @@
 #include "import-export-dialog.h"
 #include "uri-entry-dialog.h"
 #include "widgets/calendar.h"
+#include "widgets/calendar-button.h"
 #include "widgets/font-style-menu-action.h"
 #include "widgets/hyperlink-tag.h"
 
@@ -68,9 +69,9 @@ static void mw_events_updated_cb (AlmanahEventManager *event_manager, AlmanahEve
 static void mw_font_style_menu_position_func (GtkMenu *menu, int *x, int *y, gboolean *push_in, GtkMenuToolButton *button);
 static GtkMenuToolButton *mw_get_font_style_tool_button_from_action (GtkAction *action);
 static gboolean save_entry_timeout_cb (AlmanahMainWindow *self);
+static void mw_setup_toolbar (AlmanahMainWindow *main_window, AlmanahApplication *application, GtkToolbar *toolbar, GtkAction *today_action);
 
 /* GtkBuilder callbacks */
-void mw_calendar_day_selected_cb (GtkCalendar *calendar, AlmanahMainWindow *main_window);
 void mw_import_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
 void mw_export_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
 void mw_page_setup_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
@@ -88,14 +89,17 @@ void mw_search_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
 void mw_preferences_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
 void mw_about_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
 void mw_jump_to_today_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
+void mw_old_entries_activate_cb (GtkAction *action, AlmanahMainWindow *main_window);
 void mw_events_tree_view_row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, AlmanahMainWindow *main_window);
 void mw_font_style_activate_cb (AlmanahFontStyleMenuAction *action, AlmanahMainWindow *main_window);
 
+/* Other callbacks */
+void mw_calendar_day_selected_cb (AlmanahCalendarButton *calendar, AlmanahMainWindow *main_window);
+
 struct _AlmanahMainWindowPrivate {
 	GtkTextView *entry_view;
 	GtkTextBuffer *entry_buffer;
-	AlmanahCalendar *calendar;
-	GtkLabel *date_label;
+	AlmanahCalendarButton *calendar_button;
 	GtkListStore *event_store;
 	GtkTreeSelection *events_selection;
 	GtkToggleAction *bold_action;
@@ -186,10 +190,11 @@ AlmanahMainWindow *
 almanah_main_window_new (AlmanahApplication *application)
 {
 	GtkBuilder *builder;
-	AlmanahStorageManager *storage_manager;
 	AlmanahEventManager *event_manager;
 	AlmanahMainWindow *main_window;
 	AlmanahMainWindowPrivate *priv;
+	GtkToolbar *toolbar;
+	GtkAction *today_action;
 	GError *error = NULL;
 	const gchar *interface_filename = almanah_get_interface_filename ();
 	const gchar *object_names[] = {
@@ -237,8 +242,6 @@ almanah_main_window_new (AlmanahApplication *application)
 	/* Grab our child widgets */
 	priv->entry_view = GTK_TEXT_VIEW (gtk_builder_get_object (builder, "almanah_mw_entry_view"));
 	priv->entry_buffer = gtk_text_view_get_buffer (priv->entry_view);
-	priv->calendar = ALMANAH_CALENDAR (gtk_builder_get_object (builder, "almanah_mw_calendar"));
-	priv->date_label = GTK_LABEL (gtk_builder_get_object (builder, "almanah_mw_date_label"));
 	priv->event_store = GTK_LIST_STORE (gtk_builder_get_object (builder, "almanah_mw_event_store"));
 	priv->events_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (gtk_builder_get_object (builder, "almanah_mw_events_tree_view")));
 	priv->bold_action = GTK_TOGGLE_ACTION (gtk_builder_get_object (builder, "almanah_ui_bold"));;
@@ -285,11 +288,6 @@ almanah_main_window_new (AlmanahApplication *application)
 	g_signal_connect (priv->underline_action, "toggled", G_CALLBACK (mw_underline_toggled_cb), main_window);
 	g_signal_connect (priv->hyperlink_action, "toggled", (GCallback) mw_hyperlink_toggled_cb, main_window);
 
-	/* Notification for calendar changes */
-	storage_manager = almanah_application_dup_storage_manager (application);
-	almanah_calendar_set_storage_manager (priv->calendar, storage_manager);
-	g_object_unref (storage_manager);
-
 	/* Notification for event changes */
 	event_manager = almanah_application_dup_event_manager (application);
 	g_signal_connect (event_manager, "events-updated", G_CALLBACK (mw_events_updated_cb), main_window);
@@ -299,6 +297,11 @@ almanah_main_window_new (AlmanahApplication *application)
 	priv->print_settings = gtk_print_settings_new ();
 	priv->page_setup = gtk_page_setup_new ();
 
+	/* Set up the toolbar */
+	toolbar = GTK_TOOLBAR (gtk_builder_get_object (builder, "almanah_mw_toolbar"));
+	today_action = GTK_ACTION (gtk_builder_get_object (builder, "almanah_ui_jump_to_today"));
+	mw_setup_toolbar (main_window, application, toolbar, today_action);
+
 	/* Select the current day and month */
 	mw_jump_to_today_activate_cb (NULL, main_window);
 
@@ -667,7 +670,7 @@ save_entry_timeout_cb (AlmanahMainWindow *self)
 void
 almanah_main_window_select_date (AlmanahMainWindow *self, GDate *date)
 {
-	almanah_calendar_select_date (self->priv->calendar, date);
+	almanah_calendar_button_select_date (self->priv->calendar_button, date);
 }
 
 static void
@@ -1214,7 +1217,14 @@ mw_jump_to_today_activate_cb (GtkAction *action, AlmanahMainWindow *main_window)
 {
 	GDate current_date;
 	g_date_set_time_t (&current_date, time (NULL));
-	almanah_main_window_select_date (main_window, &current_date);
+	almanah_calendar_button_select_date (main_window->priv->calendar_button, &current_date);
+}
+
+void
+mw_old_entries_activate_cb (GtkAction *action, AlmanahMainWindow *main_window)
+{
+	// TODO: Show the old entries
+	g_debug ("Old entries clicked, but nothing implemented yet...");
 }
 
 /**
@@ -1349,7 +1359,7 @@ mw_events_updated_cb (AlmanahEventManager *event_manager, AlmanahEventFactoryTyp
 	GSList *_events, *events;
 	GDate date;
 
-	almanah_calendar_get_date (main_window->priv->calendar, &date);
+	almanah_calendar_button_get_date (main_window->priv->calendar_button, &date);
 	_events = almanah_event_manager_get_events (event_manager, type_id, &date);
 
 	/* Clear all the events generated by this factory out of the list store first */
@@ -1381,13 +1391,12 @@ mw_events_updated_cb (AlmanahEventManager *event_manager, AlmanahEventFactoryTyp
 }
 
 void
-mw_calendar_day_selected_cb (GtkCalendar *calendar, AlmanahMainWindow *main_window)
+mw_calendar_day_selected_cb (AlmanahCalendarButton *calendar_button, AlmanahMainWindow *main_window)
 {
 	AlmanahApplication *application;
 	AlmanahStorageManager *storage_manager;
 	AlmanahEventManager *event_manager;
 	GDate calendar_date;
-	gchar calendar_string[100];
 #ifdef ENABLE_SPELL_CHECKING
 	GtkSpell *gtkspell;
 #endif /* ENABLE_SPELL_CHECKING */
@@ -1401,11 +1410,7 @@ mw_calendar_day_selected_cb (GtkCalendar *calendar, AlmanahMainWindow *main_wind
 	save_current_entry (main_window, TRUE);
 
 	/* Update the date label */
-	almanah_calendar_get_date (main_window->priv->calendar, &calendar_date);
-
-	/* Translators: This is a strftime()-format string for the date displayed at the top of the main window. */
-	g_date_strftime (calendar_string, sizeof (calendar_string), _("%A, %e %B %Y"), &calendar_date);
-	gtk_label_set_markup (priv->date_label, calendar_string);
+	almanah_calendar_button_get_date (main_window->priv->calendar_button, &calendar_date);
 
 	/* Update the entry */
 	storage_manager = almanah_application_dup_storage_manager (application);
@@ -1481,6 +1486,35 @@ mw_events_tree_view_row_activated_cb (GtkTreeView *tree_view, GtkTreePath *path,
 	almanah_event_view (event, GTK_WINDOW (main_window));
 }
 
+static void
+mw_setup_toolbar (AlmanahMainWindow *main_window, AlmanahApplication *application, GtkToolbar *toolbar, GtkAction *today_action)
+{
+	GtkToolItem *calendar_button_item, *separator;
+	AlmanahStorageManager *storage_manager;
+
+	/* Insert a dynamic space between the text style and calendar & important.
+	 * This can't be done using the <separator/> in the UI file at the moment
+	 */
+	separator = gtk_separator_tool_item_new ();
+	gtk_separator_tool_item_set_draw (GTK_SEPARATOR_TOOL_ITEM (separator), FALSE);
+	gtk_tool_item_set_expand (separator, TRUE);
+	gtk_toolbar_insert (toolbar, separator, 2);
+
+	/* Setup the calendar button */
+	storage_manager = almanah_application_dup_storage_manager (application);
+	main_window->priv->calendar_button = ALMANAH_CALENDAR_BUTTON (almanah_calendar_button_new (storage_manager));
+	g_object_unref (storage_manager);
+	g_signal_connect (main_window->priv->calendar_button, "day-selected", G_CALLBACK (mw_calendar_day_selected_cb), main_window);
+	/* Use the same action for the today button in the dropdown window */
+	almanah_calendar_button_set_today_action (main_window->priv->calendar_button, today_action);
+
+	/* Insert the calendar button into the toolbar through a GtkToolItem but button style */
+	calendar_button_item = gtk_tool_item_new ();
+	gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (calendar_button_item)), GTK_STYLE_CLASS_RAISED);
+	gtk_container_add (GTK_CONTAINER (calendar_button_item), GTK_WIDGET (main_window->priv->calendar_button));
+	gtk_toolbar_insert (toolbar, calendar_button_item, 3);
+}
+
 #ifdef ENABLE_SPELL_CHECKING
 static void
 spell_checking_enabled_changed_cb (GSettings *settings, gchar *key, AlmanahMainWindow *self)
diff --git a/src/widgets/calendar-button.c b/src/widgets/calendar-button.c
new file mode 100644
index 0000000..d9635bd
--- /dev/null
+++ b/src/widgets/calendar-button.c
@@ -0,0 +1,391 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Almanah
+ * Copyright (C) Ãlvaro PeÃa 2011-2012 <alvaropg gmail com>
+ *
+ * Almanah is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Almanah is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Almanah.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib/gi18n.h>
+#include <config.h>
+
+#include "calendar-button.h"
+#include "calendar.h"
+#include "calendar-window.h"
+#include "interface.h"
+
+/* This enum allows to know the reason why the calendar date has been changed */
+enum {
+	NONE_EVENT = 1, /* The window is showed */
+	FIRST_EVENT,    /* The widget is instatiated the first time */
+	TODAY_EVENT,    /* The user clicks on "Today" button */
+	DAY_EVENT,      /* The user selects a concret day in the calendar widget */
+	MONTH_EVENT     /* The user changes the month, or the year clicking in the calendar widget */
+};
+
+enum {
+	DAY_SELECTED_SIGNAL,
+	LAST_SIGNAL
+};
+
+enum {
+	PROP_STORAGE_MANAGER = 1
+};
+
+static guint calendar_button_signals[LAST_SIGNAL] = { 0 };
+
+struct _AlmanahCalendarButtonPrivate {
+	GtkWidget *label;
+	GtkWidget *dock;
+	guchar user_event;
+	AlmanahCalendar *calendar;
+	GtkWidget *today_button;
+	AlmanahStorageManager *storage_manager;
+};
+
+static void almanah_calendar_button_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+static void almanah_calendar_button_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+static void almanah_calendar_button_finalize (GObject *object);
+
+static void almanah_calendar_button_dock_hiden (GtkWidget *widget, gpointer user_data);
+
+static void almanah_calendar_button_toggled (GtkToggleButton *togglebutton, gpointer user_data);
+static void almanah_calendar_button_day_selected_cb (GtkCalendar *calendar, AlmanahCalendarButton *self);
+static void almanah_calendar_button_month_changed_cb (GtkCalendar *calendar, AlmanahCalendarButton *self);
+static gboolean almanah_calendar_button_today_press_cb (GtkWidget *widget, GdkEvent *event, AlmanahCalendarButton *self);
+
+static void dock_position_func (AlmanahCalendarButton *self, gint *x, gint *y);
+
+G_DEFINE_TYPE (AlmanahCalendarButton, almanah_calendar_button, GTK_TYPE_TOGGLE_BUTTON)
+
+static void
+almanah_calendar_button_class_init (AlmanahCalendarButtonClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (AlmanahCalendarButtonPrivate));
+
+	gobject_class->get_property = almanah_calendar_button_get_property;
+	gobject_class->set_property = almanah_calendar_button_set_property;
+	gobject_class->finalize = almanah_calendar_button_finalize;
+
+	g_object_class_install_property (gobject_class, PROP_STORAGE_MANAGER,
+	                                 g_param_spec_object ("storage-manager",
+	                                                      "Storage manager", "The storage manager whose entries should be listed.",
+	                                                      ALMANAH_TYPE_STORAGE_MANAGER,
+	                                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+	/**
+	 * AlmanahCalendarButton::day-selected:
+	 * @calendar_button: the object which received the signal.
+	 *
+	 * Emitted when the user selects a day in the dock window.
+	 */
+	calendar_button_signals[DAY_SELECTED_SIGNAL] = g_signal_new ("day-selected",
+								     G_OBJECT_CLASS_TYPE (gobject_class),
+								     G_SIGNAL_RUN_FIRST,
+								     G_STRUCT_OFFSET (AlmanahCalendarButtonClass, day_selected),
+								     NULL, NULL,
+								     NULL,
+								     G_TYPE_NONE, 0);
+}
+
+static void
+almanah_calendar_button_init (AlmanahCalendarButton *self)
+{
+	GtkWidget *arrow;
+	GtkBox *main_box;
+	GtkBuilder *builder;
+	GError *error = NULL;
+	const gchar *interface_filename = almanah_get_interface_filename ();
+	const gchar *object_names[] = {
+		"almanah_calendar_window",
+		NULL
+	};
+
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ALMANAH_TYPE_CALENDAR_BUTTON, AlmanahCalendarButtonPrivate);
+	self->priv->user_event = FIRST_EVENT;
+
+	/* The button elements */
+	self->priv->label = gtk_label_new (NULL);
+	arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
+	main_box = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6));
+	gtk_box_pack_start (main_box, self->priv->label, TRUE, TRUE, 0);
+	gtk_box_pack_start (main_box, arrow, FALSE, TRUE, 0);
+	gtk_container_add (GTK_CONTAINER (self), GTK_WIDGET (main_box));
+
+	gtk_button_set_focus_on_click (GTK_BUTTON (self), TRUE);
+
+	g_signal_connect (self, "toggled", G_CALLBACK (almanah_calendar_button_toggled), NULL);
+
+	/* Calendar dock window from the UI file */
+	builder = gtk_builder_new ();
+	if (gtk_builder_add_objects_from_file (builder, interface_filename, (gchar **) object_names, &error) == FALSE) {
+		g_warning (_("UI file \"%s\" could not be loaded: %s"), interface_filename, error->message);
+		g_error_free (error);
+		g_object_unref (builder);
+
+		return;
+	}
+
+	gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
+	self->priv->dock = GTK_WIDGET (gtk_builder_get_object (builder, "almanah_calendar_window"));
+	if (self->priv->dock == NULL) {
+		g_warning (_("Can't load calendar window object from UI file"));
+		g_object_unref (builder);
+
+		return;
+	}
+
+	g_signal_connect (self->priv->dock, "hide", G_CALLBACK (almanah_calendar_button_dock_hiden), self);
+
+	/* The calendar widget */
+	self->priv->calendar = ALMANAH_CALENDAR (gtk_builder_get_object (builder, "almanah_cw_calendar"));
+	g_object_ref (self->priv->calendar);
+	g_signal_connect (self->priv->calendar, "day-selected", G_CALLBACK (almanah_calendar_button_day_selected_cb), self);
+	g_signal_connect (self->priv->calendar, "month_changed", G_CALLBACK (almanah_calendar_button_month_changed_cb), self);
+
+	/* Today button */
+	self->priv->today_button = GTK_WIDGET (gtk_builder_get_object (builder, "almanah_cw_today_button"));
+	g_signal_connect (self->priv->today_button, "button-press-event", G_CALLBACK (almanah_calendar_button_today_press_cb), self);
+
+	g_object_unref (builder);
+}
+
+static void
+almanah_calendar_button_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	AlmanahCalendarButtonPrivate *priv = ALMANAH_CALENDAR_BUTTON (object)->priv;
+
+	switch (property_id) {
+		case PROP_STORAGE_MANAGER:
+			g_value_set_object (value, priv->storage_manager);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static void
+almanah_calendar_button_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	AlmanahCalendarButton *self = ALMANAH_CALENDAR_BUTTON (object);
+
+	switch (property_id) {
+		case PROP_STORAGE_MANAGER:
+			almanah_calendar_button_set_storage_manager (self, g_value_get_object (value));
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static void
+almanah_calendar_button_finalize (GObject *object)
+{
+	AlmanahCalendarButtonPrivate *priv = ALMANAH_CALENDAR_BUTTON (object)->priv;
+
+	g_clear_object (&priv->calendar);
+	g_clear_object (&priv->storage_manager);
+
+	/* Chain up to the parent class */
+	G_OBJECT_CLASS (almanah_calendar_button_parent_class)->finalize (object);
+}
+
+/**
+ * Calculate the window position
+ */
+static void
+dock_position_func (AlmanahCalendarButton *self, gint *x, gint *y)
+{
+	GdkScreen *screen;
+	GdkRectangle monitor;
+	GtkAllocation allocation;
+	GtkRequisition dock_req;
+	gint new_x, new_y, monitor_num;
+	AlmanahCalendarWindow *calendar_window = ALMANAH_CALENDAR_WINDOW (self->priv->dock);
+
+	/* Get the screen and monitor geometry */
+	screen = gtk_widget_get_screen (GTK_WIDGET (self));
+	monitor_num = gdk_screen_get_monitor_at_window (screen, gtk_widget_get_window (GTK_WIDGET (self)));
+	if (monitor_num < 0)
+		monitor_num = 0;
+	gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+	/* Get the AlmanahCalendarButton position */
+	gtk_widget_get_allocation (GTK_WIDGET (self), &allocation);
+	gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (self)), &new_x, &new_y);
+	/* The dock window starting position is over the calendar button widget */
+	new_x += allocation.x;
+	new_y += allocation.y;
+
+	gtk_widget_get_preferred_size (GTK_WIDGET (calendar_window), &dock_req, NULL);
+	if (new_x + dock_req.width > monitor.x + monitor.width) {
+		/* Move the required pixels to the left if the dock don't showed complety
+		 * in the screen
+		 */
+		new_x -= (new_x + dock_req.width) - (monitor.x + monitor.width);
+	}
+
+	if ((new_y + allocation.height + dock_req.height) <= monitor.y + monitor.height) {
+		/*The dock window height isn't bigger than the monitor size */
+		new_y += allocation.height;
+	} else if (new_y - dock_req.height >= monitor.y) {
+		/* If the dock window height can't showed complety in the monitor,
+		 * and the dock height isn't to bigg to show on top the calendar button
+		 * move it on top of the calendar button
+		 */
+		new_y -= dock_req.height;
+	} else if (monitor.y + monitor.height - (new_y + allocation.height) > new_y) {
+		/* in other case, we show under the calendar button if the space is enought */
+		new_y += allocation.height;
+	} else {
+		/* we need to put the dock in somewhere... even the monitor is to small */
+		new_y -= dock_req.height;
+	}
+
+	/* Put the dock window in the correct screen */
+	gtk_window_set_screen (GTK_WINDOW (calendar_window), screen);
+
+	*x = new_x;
+	*y = new_y;
+}
+
+static void
+almanah_calendar_button_dock_hiden (GtkWidget *widget, gpointer user_data)
+{
+	/* Reset the calendar user event and toggle off the button */
+	ALMANAH_CALENDAR_BUTTON (user_data)->priv->user_event = NONE_EVENT;
+	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (user_data), FALSE);
+}
+
+static void
+almanah_calendar_button_toggled (GtkToggleButton *togglebutton, gpointer user_data)
+{
+	gint x, y;
+	AlmanahCalendarButton *self;
+	GtkStyleContext *style_context;
+
+	self = ALMANAH_CALENDAR_BUTTON (togglebutton);
+	style_context = gtk_widget_get_style_context (GTK_WIDGET (togglebutton));
+	if (gtk_toggle_button_get_active (togglebutton)) {
+		/* FIXME: Changing the style don't work!?! */
+		gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_MENUBAR);
+		gtk_style_context_add_class (style_context, GTK_STYLE_CLASS_MENUITEM);
+		/* Show the dock */
+		dock_position_func (self, &x, &y);
+		almanah_calendar_window_popup (ALMANAH_CALENDAR_WINDOW (self->priv->dock));
+		gtk_window_move (GTK_WINDOW (self->priv->dock), x, y);
+	} else {
+		gtk_style_context_remove_class (style_context, GTK_STYLE_CLASS_MENUBAR);
+		gtk_style_context_remove_class (style_context, GTK_STYLE_CLASS_MENUITEM);
+		/* Isn't necesary to hide the dock */
+	}
+
+	gtk_widget_reset_style (GTK_WIDGET (togglebutton));
+}
+
+static void
+almanah_calendar_button_day_selected_cb (GtkCalendar *calendar, AlmanahCalendarButton *self)
+{
+	GDate calendar_date;
+	gchar calendar_string[100];
+
+	almanah_calendar_get_date (self->priv->calendar, &calendar_date);
+	/* Translators: This is a strftime()-format string for the date displayed at the top of the main window. */
+	g_date_strftime (calendar_string, sizeof (calendar_string), _("%A, %e %B %Y"), &calendar_date);
+	gtk_label_set_text (GTK_LABEL (self->priv->label), calendar_string);
+	if (self->priv->user_event < DAY_EVENT) {
+		/* Only hide the dock window when the user has clicked in a calendar day */
+		self->priv->user_event = DAY_EVENT;
+		almanah_calendar_window_popdown (ALMANAH_CALENDAR_WINDOW (self->priv->dock));
+	}
+
+	self->priv->user_event = NONE_EVENT;
+
+	/* Emmits the signal at the end */
+	g_signal_emit (self, calendar_button_signals[DAY_SELECTED_SIGNAL], 0);
+}
+
+static void
+almanah_calendar_button_month_changed_cb (GtkCalendar *calendar, AlmanahCalendarButton *self)
+{
+	if (self->priv->user_event != TODAY_EVENT) {
+		/* Save the month changed event just if the user hasn't click the today button
+		 * beacuse the dock window should not hide in this case */
+		self->priv->user_event = MONTH_EVENT;
+	}
+}
+
+static gboolean
+almanah_calendar_button_today_press_cb (GtkWidget *widget, GdkEvent *event, AlmanahCalendarButton *self)
+{
+	/* Save this event to not hide the dock window */
+	self->priv->user_event = TODAY_EVENT;
+
+	return FALSE;
+}
+
+GtkWidget *
+almanah_calendar_button_new (AlmanahStorageManager *storage_manager)
+{
+	g_return_val_if_fail (ALMANAH_IS_STORAGE_MANAGER (storage_manager), NULL);
+	return GTK_WIDGET (g_object_new (ALMANAH_TYPE_CALENDAR_BUTTON, "storage-manager", storage_manager, NULL));
+}
+
+void
+almanah_calendar_button_set_storage_manager (AlmanahCalendarButton *self, AlmanahStorageManager *storage_manager)
+{
+	g_return_if_fail (ALMANAH_IS_CALENDAR_BUTTON (self));
+	g_return_if_fail (ALMANAH_IS_STORAGE_MANAGER (storage_manager));
+
+	g_clear_object (&self->priv->storage_manager);
+	self->priv->storage_manager = storage_manager;
+	g_object_ref (self->priv->storage_manager);
+
+	if (self->priv->calendar != NULL && ALMANAH_IS_CALENDAR (self->priv->calendar)) {
+		almanah_calendar_set_storage_manager (self->priv->calendar, self->priv->storage_manager);
+	}
+}
+
+void
+almanah_calendar_button_set_today_action (AlmanahCalendarButton *self, GtkAction *action)
+{
+	g_return_if_fail (ALMANAH_IS_CALENDAR_BUTTON (self));
+	g_return_if_fail (GTK_IS_ACTION (action));
+
+	if (GTK_IS_BUTTON (self->priv->today_button)) {
+		gtk_activatable_set_related_action (GTK_ACTIVATABLE (self->priv->today_button), action);
+	}
+}
+
+void
+almanah_calendar_button_select_date (AlmanahCalendarButton *self, GDate *date)
+{
+	g_return_if_fail (ALMANAH_IS_CALENDAR_BUTTON (self));
+	g_return_if_fail (date != NULL);
+
+	almanah_calendar_select_date (self->priv->calendar, date);
+}
+
+void
+almanah_calendar_button_get_date (AlmanahCalendarButton *self, GDate *date)
+{
+	g_return_if_fail (ALMANAH_IS_CALENDAR_BUTTON (self));
+	g_return_if_fail (date != NULL);
+
+	almanah_calendar_get_date (self->priv->calendar, date);
+}
diff --git a/src/widgets/calendar-button.h b/src/widgets/calendar-button.h
new file mode 100644
index 0000000..2e8fc3e
--- /dev/null
+++ b/src/widgets/calendar-button.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Almanah
+ * Copyright (C) Ãlvaro PeÃa 2011 <alvaropg gmail com>
+ *
+ * Almanah is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Almanah is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Almanah.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALMANAH_CALENDAR_BUTTON_H
+#define ALMANAH_CALENDAR_BUTTON_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "widgets/calendar.h"
+#include "storage-manager.h"
+
+G_BEGIN_DECLS
+
+#define ALMANAH_TYPE_CALENDAR_BUTTON		(almanah_calendar_button_get_type ())
+#define ALMANAH_CALENDAR_BUTTON(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), ALMANAH_TYPE_CALENDAR_BUTTON, AlmanahCalendarButton))
+#define ALMANAH_CALENDAR_BUTTON_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), ALMANAH_TYPE_CALENDAR_BUTTON, AlmanahCalendarButtonClass))
+#define ALMANAH_IS_CALENDAR_BUTTON(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), ALMANAH_TYPE_CALENDAR_BUTTON))
+#define ALMANAH_IS_CALENDAR_BUTTON_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), ALMANAH_TYPE_CALENDAR_BUTTON))
+#define ALMANAH_CALENDAR_BUTTON_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), ALMANAH_TYPE_CALENDAR_BUTTON, AlmanahCalendarButtonClass))
+
+typedef struct _AlmanahCalendarButtonPrivate	AlmanahCalendarButtonPrivate;
+
+typedef struct {
+	GtkToggleButton parent;
+	AlmanahCalendarButtonPrivate *priv;
+} AlmanahCalendarButton;
+
+typedef struct {
+	GtkToggleButtonClass parent;
+	void (* day_selected) (AlmanahCalendarButton *self);
+} AlmanahCalendarButtonClass;
+
+GType almanah_calendar_button_get_type (void) G_GNUC_CONST;
+GtkWidget *almanah_calendar_button_new (AlmanahStorageManager *storage_manager) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+void almanah_calendar_button_set_today_action (AlmanahCalendarButton *self, GtkAction *action);
+void almanah_calendar_button_set_storage_manager (AlmanahCalendarButton *self, AlmanahStorageManager *storage_manager);
+void almanah_calendar_button_select_date (AlmanahCalendarButton *self, GDate *date);
+void almanah_calendar_button_get_date (AlmanahCalendarButton *self, GDate *date);
+
+G_END_DECLS
+
+#endif /* !ALMANAH_CALENDAR_BUTTON_H */
diff --git a/src/widgets/calendar-window.c b/src/widgets/calendar-window.c
new file mode 100644
index 0000000..74a77bd
--- /dev/null
+++ b/src/widgets/calendar-window.c
@@ -0,0 +1,165 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Almanah
+ * Copyright (C) Ãlvaro PeÃa 2012 <alvaropg gmail com>
+ *
+ * Almanah is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Almanah is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Almanah.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <glib/gi18n.h>
+
+#include "calendar-window.h"
+#include "widgets/calendar.h"
+#include "interface.h"
+
+static void show (GtkWidget *self);
+static gboolean button_press_event (GtkWidget *self, GdkEventButton *event);
+static gboolean key_press_event (GtkWidget *self, GdkEventKey *event);
+
+struct _AlmanahCalendarWindowPrivate {
+	GdkDevice *grab_pointer;
+};
+
+G_DEFINE_TYPE (AlmanahCalendarWindow, almanah_calendar_window, GTK_TYPE_WINDOW)
+#define ALMANAH_CALENDAR_WINDOW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ALMANAH_TYPE_CALENDAR_WINDOW, AlmanahCalendarWindowPrivate))
+
+static void
+almanah_calendar_window_class_init (AlmanahCalendarWindowClass *klass)
+{
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+	g_type_class_add_private (klass, sizeof (AlmanahCalendarWindowPrivate));
+
+	widget_class->show = show;
+	widget_class->button_press_event = button_press_event;
+	widget_class->key_press_event = key_press_event;
+}
+
+static void
+almanah_calendar_window_init (AlmanahCalendarWindow *self)
+{
+	self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ALMANAH_TYPE_CALENDAR_WINDOW, AlmanahCalendarWindowPrivate);
+}
+
+static void
+show (GtkWidget *self)
+{
+	GdkDevice *device, *keyboard, *pointer;
+	GdkWindow *window;
+
+	GTK_WIDGET_CLASS (almanah_calendar_window_parent_class)->show (self);
+
+	window = gtk_widget_get_window (self);
+
+	device = gtk_get_current_event_device ();
+	switch (gdk_device_get_source (device)) {
+		case GDK_SOURCE_KEYBOARD:
+			keyboard = device;
+			pointer = gdk_device_get_associated_device (device);
+			break;
+		case GDK_SOURCE_MOUSE:
+		case GDK_SOURCE_PEN:
+		case GDK_SOURCE_ERASER:
+		case GDK_SOURCE_CURSOR:
+			pointer = device;
+			keyboard = gdk_device_get_associated_device (device);
+			break;
+		default:
+			g_warning (_("Unknown input device"));
+			return;
+	}
+
+	gtk_grab_add (self);
+
+	gdk_device_grab (keyboard, window,
+			 GDK_OWNERSHIP_WINDOW, TRUE,
+			 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+			 NULL, GDK_CURRENT_TIME);
+
+	gdk_device_grab (pointer, window,
+			 GDK_OWNERSHIP_WINDOW, TRUE,
+			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+			 GDK_POINTER_MOTION_MASK,
+			 NULL, GDK_CURRENT_TIME);
+
+	ALMANAH_CALENDAR_WINDOW_GET_PRIVATE(ALMANAH_CALENDAR_WINDOW (self))->grab_pointer = pointer;
+}
+
+static gboolean
+button_press_event (GtkWidget *self, GdkEventButton *event)
+{
+	GtkAllocation allocation;
+	gint window_x, window_y;
+
+	if (event->type != GDK_BUTTON_PRESS) {
+		return TRUE;
+	}
+
+	/* Take the dock window position and dimensions */
+	gdk_window_get_position (gtk_widget_get_window (self), &window_x, &window_y);
+	gtk_widget_get_allocation (self, &allocation);
+
+	/* Hide the dock when the user clicks out of the dock window */
+	if (event->x_root < window_x || event->x_root > window_x + allocation.width ||
+	    event->y_root < window_y || event->y_root > window_y + allocation.height) {
+		almanah_calendar_window_popdown (ALMANAH_CALENDAR_WINDOW (self));
+	}
+
+	return FALSE;
+}
+
+static gboolean
+key_press_event (GtkWidget *self, GdkEventKey *event)
+{
+	if (event->keyval != GDK_KEY_Escape) {
+		return FALSE;
+	}
+
+	almanah_calendar_window_popdown (ALMANAH_CALENDAR_WINDOW (self));
+
+	return TRUE;
+}
+
+GtkWidget *
+almanah_calendar_window_new (void)
+{
+	return GTK_WIDGET (g_object_new (ALMANAH_TYPE_CALENDAR_WINDOW, NULL));
+}
+
+void
+almanah_calendar_window_popup (AlmanahCalendarWindow *self)
+{
+	g_return_if_fail (ALMANAH_IS_CALENDAR_WINDOW (self));
+
+	gtk_widget_show_all (GTK_WIDGET (self));
+}
+
+void
+almanah_calendar_window_popdown (AlmanahCalendarWindow *self)
+{
+	GdkDevice *pointer, *keyboard;
+
+	g_return_if_fail (ALMANAH_IS_CALENDAR_WINDOW (self));
+
+	pointer = self->priv->grab_pointer;
+	gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
+	keyboard = gdk_device_get_associated_device (pointer);
+	if (keyboard)
+		gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
+
+	gtk_grab_remove (GTK_WIDGET (self));
+
+	gtk_widget_hide (GTK_WIDGET (self));
+}
diff --git a/src/widgets/calendar-window.h b/src/widgets/calendar-window.h
new file mode 100644
index 0000000..88b48c2
--- /dev/null
+++ b/src/widgets/calendar-window.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Almanah
+ * Copyright (C) Ãlvaro PeÃa 2012 <alvaropg gmail com>
+ *
+ * Almanah is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Almanah is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Almanah.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ALMANAH_CALENDAR_WINDOW_H
+#define ALMANAH_CALENDAR_WINDOW_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "application.h"
+
+G_BEGIN_DECLS
+
+#define ALMANAH_TYPE_CALENDAR_WINDOW            (almanah_calendar_window_get_type ())
+#define ALMANAH_CALENDAR_WINDOW(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), ALMANAH_TYPE_CALENDAR_WINDOW, AlmanahCalendarWindow))
+#define ALMANAH_CALENDAR_WINDOW_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), ALMANAH_TYPE_CALENDAR_WINDOW, AlmanahCalendarWindowClass))
+#define ALMANAH_IS_CALENDAR_WINDOW(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), ALMANAH_TYPE_CALENDAR_WINDOW))
+#define ALMANAH_IS_CALENDAR_WINDOW_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), ALMANAH_TYPE_CALENDAR_WINDOW))
+#define ALMANAH_CALENDAR_WINDOW_GET_CLASS(o)	(G_TYPE_INSTANCE_GET_CLASS ((o), ALMANAH_TYPE_CALENDAR_WINDOW, AlmanahCalendarWindowClass))
+
+typedef struct _AlmanahCalendarWindow        AlmanahCalendarWindow;
+typedef struct _AlmanahCalendarWindowClass   AlmanahCalendarWindowClass;
+typedef struct _AlmanahCalendarWindowPrivate AlmanahCalendarWindowPrivate;
+
+struct _AlmanahCalendarWindow{
+	GtkWindow parent;
+	AlmanahCalendarWindowPrivate *priv;
+};
+
+struct _AlmanahCalendarWindowClass {
+	GtkWindowClass parent;
+};
+
+GType almanah_calendar_window_get_type (void) G_GNUC_CONST;
+
+GtkWidget *almanah_calendar_window_new (void) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+
+void almanah_calendar_window_popup (AlmanahCalendarWindow *self);
+void almanah_calendar_window_popdown (AlmanahCalendarWindow *self);
+
+G_END_DECLS
+
+#endif /* !ALMANAH_CALENDAR_WINDOW_H */



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