aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog289
-rwxr-xr-xconfigure20
-rw-r--r--configure.ac4
-rw-r--r--data/com.canonical.indicator.datetime.gschema.xml7
-rw-r--r--data/datetime-dialog.ui40
-rw-r--r--libmap/cc-timezone-map.c16
-rwxr-xr-xltmain.sh4
-rw-r--r--src/datetime-prefs-locations.c192
-rw-r--r--src/datetime-prefs-locations.h2
-rw-r--r--src/datetime-prefs.c120
-rw-r--r--src/datetime-service.c192
-rw-r--r--src/dbus-shared.h4
-rw-r--r--src/indicator-datetime.c181
-rw-r--r--src/settings-shared.h5
-rw-r--r--src/timezone-completion.c214
-rw-r--r--src/utils.c2
16 files changed, 1062 insertions, 230 deletions
diff --git a/ChangeLog b/ChangeLog
index f985eff..d0304e9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,294 @@
# Generated by Makefile. Do not edit.
+2011-03-31 Ted Gould <ted@gould.cx>
+
+ 0.2.1
+
+2011-03-31 Ted Gould <ted@gould.cx>
+
+ Switching to using SystemIdleHintChanged
+
+2011-03-31 karl-qdh <karl@qdh.org.uk>
+
+ Switched to using SystemIdleHintChanged from ActiveState, appears ConsoleKit might have changed recently.
+
+2011-03-31 karl-qdh <karl@qdh.org.uk>
+
+ Merged back with head
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Fix up icons and give them tool tips
+
+2011-03-30 Michael Terry <mike@mterry.name>
+
+ add error icon to main timezone entry
+
+2011-03-30 Michael Terry <mike@mterry.name>
+
+ add tooltip to error icon
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Fix marking and clean up event handling in the indicator and service
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Removing a warning that will occur on the default GTK properties
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Be a bit smarter about handling the the locale
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Syncing with Karl's branch
+
+2011-03-30 karl-qdh <karl@qdh.org.uk>
+
+ Might not like that signal notation
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Setting the default _WITH_DAY to be 12_WITH_DAY
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Changing code to recycle the appointment menu items for a cleaner switching of days
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Disable the appointments on date or month change to make it show that they're being updated and aren't currently valid
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Ensure that the marks get cleared on day changes that go across monthly boundries as well
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Protecting against the widgets being NULL at startup
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Check for the signal name in the handler
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Moving the registration of the type handlers into the init so that they'll not execute more than once.
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Update the appointments in the idle loop so we can get those signals returned promptly!
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Clear marks on month changes
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Protecting against NULL values
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Cleaning up debug output
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Making the right size group more real to remove an annoying error
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Making sure to get the inital values of the calendar properties
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Some debugging info
+
+2011-03-30 Ted Gould <ted@gould.cx>
+
+ Switching to one variable with all the marks in it
+
+2011-03-30 karl-qdh <karl@qdh.org.uk>
+
+ Potential fix for suspend issue suggested by njpatel
+
+2011-03-30 karl-qdh <karl@qdh.org.uk>
+
+ Move start timer into an idle so we have a chance to actually create the menu items
+
+2011-03-30 karl-qdh <karl@qdh.org.uk>
+
+ Made marking work when you change month, still needs more work to get it to do it on startup properly.
+
+2011-03-29 karl-qdh <karl@qdh.org.uk>
+
+ Adding tedg's suggested change to the property sending, no change in signals being received by the other side.
+
+2011-03-25 karl-qdh <karl@qdh.org.uk>
+
+ Try splitting the function see if that works
+
+2011-03-25 karl-qdh <karl@qdh.org.uk>
+
+ Merged
+
+2011-03-23 karl-qdh <karl@qdh.org.uk>
+
+ merged back with sniffles branch and added some changes to the resetdate, which also effects the marked days.
+
+2011-03-23 karl-qdh <karl@qdh.org.uk>
+
+ changes for bug #649800 - requires dbusmenu to be released
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Adding a preferences for prefered timezone
+
+2011-03-29 Michael Terry <mike@mterry.name>
+
+ remember user's preferred location name for main timezone
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Adding a error icon
+
+2011-03-29 Michael Terry <mike@mterry.name>
+
+ show error icon if user focuses out of location entry when it has an non-location value
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Protect against not having an entry
+
+2011-03-29 Michael Terry <mike@mterry.name>
+
+ don't call complete() unless we have an entry
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Handle enter on the default case by selecting the first entry instead of entering a blank item.
+
+2011-03-28 Michael Terry <mike@mterry.name>
+
+ Don't allow enter presses to leave non-timezone content in the model
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ A11y text
+
+2011-03-28 Michael Terry <mike@mterry.name>
+
+ add missing a11y descriptions
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Make the locations dialog non-modal but resurface when needed.
+
+2011-03-29 Michael Terry <mike@mterry.name>
+
+ treat locations dialog not as a modal dialog, but rather one that can be dismissed by interacting with the main dialog
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Fix crash with GVariantBuilder, unref a timedate and ensure that we always have a separator
+
+2011-03-24 Michael Terry <mike@mterry.name>
+
+ fix memory leak that also prevented us noticing when the timezone got updated
+
+2011-03-24 Michael Terry <mike@mterry.name>
+
+ show location separator even if no locations (since we always have the current location
+
+2011-03-24 Michael Terry <mike@mterry.name>
+
+ fix crash when emptying location list
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Put in timeouts to save settings on idle
+
+2011-03-24 Michael Terry <mike@mterry.name>
+
+ update locations gsettings as soon as changes as made, not just when the dialog is closed
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Update to map to make it lovely and UTC fixes
+
+2011-03-29 Michael Terry <mike@mterry.name>
+
+ use background color for insensitive map
+
+2011-03-24 Michael Terry <mike@mterry.name>
+
+ make map look insensitive if it is
+
+2011-03-24 Michael Terry <mike@mterry.name>
+
+ drop debugging line and update times when user selects a zone
+
+2011-03-23 Michael Terry <mike@mterry.name>
+
+ add utc to relevant results
+
+2011-03-23 Michael Terry <mike@mterry.name>
+
+ add bevel above location buttons
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Protect our privates when being cancelled
+
+2011-03-24 Michael Terry <mike@mterry.name>
+
+ don't access priv pointer if we've cancelled an async operation
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Fix case statement brackets
+
+2011-03-28 karl-qdh <karl@qdh.org.uk>
+
+ Make switch statement more consistent might fix bug #743394 seems to be a weirdness in C related to;
+ http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37231
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Ensure calendar is always shown
+
+2011-03-28 karl-qdh <karl@qdh.org.uk>
+
+ Show calendar widget always
+
+2011-03-29 Ted Gould <ted@gould.cx>
+
+ Adjusting the timer so it appears more consistent
+
+2011-03-24 karl-qdh <karl@qdh.org.uk>
+
+ Change timer to 999ms
+
+2011-03-24 karl-qdh <karl@qdh.org.uk>
+
+ Merged mterry's changes
+
+2011-03-28 Ted Gould <ted@gould.cx>
+
+ Clean up tree model usage and sort the items in the popup list
+
+2011-03-23 Michael Terry <mike@mterry.name>
+
+ cleanup another instance of GValue
+
+2011-03-23 Michael Terry <mike@mterry.name>
+
+ sort locations by name, starting with prefixes
+
+2011-03-23 Michael Terry <mike@mterry.name>
+
+ cleanup locations dialog column usage
+
2011-03-23 Ted Gould <ted@gould.cx>
0.2.0
diff --git a/configure b/configure
index bd49efa..c788536 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.67 for indicator-datetime 0.2.0.
+# Generated by GNU Autoconf 2.67 for indicator-datetime 0.2.1.
#
# Report bugs to <ted@canonical.com>.
#
@@ -703,8 +703,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='indicator-datetime'
PACKAGE_TARNAME='indicator-datetime'
-PACKAGE_VERSION='0.2.0'
-PACKAGE_STRING='indicator-datetime 0.2.0'
+PACKAGE_VERSION='0.2.1'
+PACKAGE_STRING='indicator-datetime 0.2.1'
PACKAGE_BUGREPORT='ted@canonical.com'
PACKAGE_URL=''
@@ -1502,7 +1502,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures indicator-datetime 0.2.0 to adapt to many kinds of systems.
+\`configure' configures indicator-datetime 0.2.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1573,7 +1573,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of indicator-datetime 0.2.0:";;
+ short | recursive ) echo "Configuration of indicator-datetime 0.2.1:";;
esac
cat <<\_ACEOF
@@ -1701,7 +1701,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-indicator-datetime configure 0.2.0
+indicator-datetime configure 0.2.1
generated by GNU Autoconf 2.67
Copyright (C) 2010 Free Software Foundation, Inc.
@@ -2072,7 +2072,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by indicator-datetime $as_me 0.2.0, which was
+It was created by indicator-datetime $as_me 0.2.1, which was
generated by GNU Autoconf 2.67. Invocation command line was
$ $0 $@
@@ -2893,7 +2893,7 @@ fi
# Define the identity of the package.
PACKAGE=indicator-datetime
- VERSION=0.2.0
+ VERSION=0.2.1
cat >>confdefs.h <<_ACEOF
@@ -14945,7 +14945,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by indicator-datetime $as_me 0.2.0, which was
+This file was extended by indicator-datetime $as_me 0.2.1, which was
generated by GNU Autoconf 2.67. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -15011,7 +15011,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-indicator-datetime config.status 0.2.0
+indicator-datetime config.status 0.2.1
configured by $0, generated by GNU Autoconf 2.67,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index ef49e53..d1de2be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,11 +1,11 @@
-AC_INIT(indicator-datetime, 0.2.0, ted@canonical.com)
+AC_INIT(indicator-datetime, 0.2.1, ted@canonical.com)
AC_COPYRIGHT([Copyright 2009,2010 Canonical])
AC_PREREQ(2.53)
AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(indicator-datetime, 0.2.0)
+AM_INIT_AUTOMAKE(indicator-datetime, 0.2.1)
AM_MAINTAINER_MODE
diff --git a/data/com.canonical.indicator.datetime.gschema.xml b/data/com.canonical.indicator.datetime.gschema.xml
index b33f34e..8ce75e6 100644
--- a/data/com.canonical.indicator.datetime.gschema.xml
+++ b/data/com.canonical.indicator.datetime.gschema.xml
@@ -100,5 +100,12 @@
indicator-datetime menu.
</description>
</key>
+ <key name="timezone-name" type="s">
+ <default>''</default>
+ <summary>The name of the current timezone</summary>
+ <description>
+ Some timezones can be known by many different cities or names. This setting describes how the current zone prefers to be named. Format is "TIMEZONE NAME" (e.g. "America/New_York Boston" to name the New_York zone Boston).
+ </description>
+ </key>
</schema>
</schemalist>
diff --git a/data/datetime-dialog.ui b/data/datetime-dialog.ui
index 7545227..8479482 100644
--- a/data/datetime-dialog.ui
+++ b/data/datetime-dialog.ui
@@ -7,15 +7,9 @@
<property name="step_increment">86400</property>
<property name="page_increment">864000</property>
</object>
- <object class="GtkAdjustment" id="timeAdjustment">
- <property name="upper">1.8446744073709552e+19</property>
- <property name="step_increment">60</property>
- <property name="page_increment">3600</property>
- </object>
<object class="GtkWindow" id="locationsDialog">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Locations</property>
- <property name="modal">True</property>
<property name="default_width">300</property>
<property name="default_height">200</property>
<property name="destroy_with_parent">True</property>
@@ -47,6 +41,17 @@
</packing>
</child>
<child>
+ <object class="GtkHSeparator" id="hseparator1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkHBox" id="hbox10">
<property name="visible">True</property>
<property name="can_focus">False</property>
@@ -55,8 +60,12 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <property name="tooltip_text" translatable="yes">Add a Location…</property>
<property name="use_action_appearance">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="addButton-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Add a Location…</property>
+ </object>
+ </child>
<child>
<object class="GtkImage" id="addImage">
<property name="visible">True</property>
@@ -76,8 +85,12 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
- <property name="tooltip_text" translatable="yes">Remove This Location</property>
<property name="use_action_appearance">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="removeButton-atkobject">
+ <property name="AtkObject::accessible-description" translatable="yes">Remove This Location</property>
+ </object>
+ </child>
<child>
<object class="GtkImage" id="removeImage">
<property name="visible">True</property>
@@ -96,7 +109,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">1</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
@@ -110,8 +123,17 @@
<column type="gchararray"/>
<!-- column-name Zone -->
<column type="gchararray"/>
+ <!-- column-name Visible Name -->
+ <column type="gchararray"/>
+ <!-- column-name Icon -->
+ <column type="gchararray"/>
</columns>
</object>
+ <object class="GtkAdjustment" id="timeAdjustment">
+ <property name="upper">1.8446744073709552e+19</property>
+ <property name="step_increment">60</property>
+ <property name="page_increment">3600</property>
+ </object>
<object class="GtkWindow" id="timeDateDialog">
<property name="can_focus">False</property>
<property name="border_width">5</property>
diff --git a/libmap/cc-timezone-map.c b/libmap/cc-timezone-map.c
index ec12c84..7b7d704 100644
--- a/libmap/cc-timezone-map.c
+++ b/libmap/cc-timezone-map.c
@@ -766,13 +766,23 @@ cc_timezone_map_draw (GtkWidget *widget,
gchar *file;
GError *err = NULL;
gdouble pointx, pointy;
+ gdouble alpha = 1.0;
+ GtkStyle *style;
char buf[16];
gtk_widget_get_allocation (widget, &alloc);
+ style = gtk_widget_get_style (widget);
+
+ /* Check if insensitive */
+ if (gtk_widget_get_state (widget) == GTK_STATE_INSENSITIVE)
+ alpha = 0.5;
+
/* paint background */
- gdk_cairo_set_source_pixbuf (cr, priv->background, 0, 0);
+ gdk_cairo_set_source_color (cr, &style->bg[gtk_widget_get_state (widget)]);
cairo_paint (cr);
+ gdk_cairo_set_source_pixbuf (cr, priv->background, 0, 0);
+ cairo_paint_with_alpha (cr, alpha);
/* paint watermark */
if (priv->watermark) {
@@ -813,7 +823,7 @@ cc_timezone_map_draw (GtkWidget *widget,
alloc.height, GDK_INTERP_BILINEAR);
gdk_cairo_set_source_pixbuf (cr, hilight, 0, 0);
- cairo_paint (cr);
+ cairo_paint_with_alpha (cr, alpha);
g_object_unref (hilight);
g_object_unref (orig_hilight);
}
@@ -836,7 +846,7 @@ cc_timezone_map_draw (GtkWidget *widget,
if (pin)
{
gdk_cairo_set_source_pixbuf (cr, pin, pointx - 8, pointy - 14);
- cairo_paint (cr);
+ cairo_paint_with_alpha (cr, alpha);
g_object_unref (pin);
}
diff --git a/ltmain.sh b/ltmain.sh
index 6765090..fa4b1e1 100755
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -65,7 +65,7 @@
# compiler: $LTCC
# compiler flags: $LTCFLAGS
# linker: $LD (gnu? $with_gnu_ld)
-# $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu2
+# $progname: (GNU libtool) 2.2.6b Debian-2.2.6b-2ubuntu3
# automake: $automake_version
# autoconf: $autoconf_version
#
@@ -73,7 +73,7 @@
PROGRAM=ltmain.sh
PACKAGE=libtool
-VERSION="2.2.6b Debian-2.2.6b-2ubuntu2"
+VERSION="2.2.6b Debian-2.2.6b-2ubuntu3"
TIMESTAMP=""
package_revision=1.3017
diff --git a/src/datetime-prefs-locations.c b/src/datetime-prefs-locations.c
index 0c9a93c..9c23a40 100644
--- a/src/datetime-prefs-locations.c
+++ b/src/datetime-prefs-locations.c
@@ -35,6 +35,15 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define DATETIME_DIALOG_UI_FILE PKGDATADIR "/datetime-dialog.ui"
+#define COL_NAME 0
+#define COL_TIME 1
+#define COL_ZONE 2
+#define COL_VISIBLE_NAME 3
+#define COL_ICON 4
+
+static gboolean update_times (GtkWidget * dlg);
+static void save_when_idle (GtkWidget * dlg);
+
static void
handle_add (GtkWidget * button, GtkTreeView * tree)
{
@@ -83,37 +92,45 @@ handle_edit (GtkCellRendererText * renderer, gchar * path, gchar * new_text,
{
GtkTreeIter iter;
+ // Manual user edits are always wrong (unless they are undoing a previous
+ // edit), so we set the error icon here if needed. Common way to get to
+ // this code path is to lose entry focus.
if (gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path)) {
- gtk_list_store_set (store, &iter, 0, new_text, -1);
+ const gchar * name;
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_NAME, &name, -1);
+ gboolean correct = g_strcmp0 (name, new_text) == 0;
+
+ gtk_list_store_set (store, &iter,
+ COL_VISIBLE_NAME, new_text,
+ COL_ICON, correct ? NULL : GTK_STOCK_DIALOG_ERROR,
+ -1);
}
}
static gboolean
timezone_selected (GtkEntryCompletion * widget, GtkTreeModel * model,
- GtkTreeIter * iter, gpointer user_data)
+ GtkTreeIter * iter, GtkWidget * dlg)
{
- GValue zone_value = {0}, name_value = {0};
const gchar * zone, * name;
- gtk_tree_model_get_value (model, iter, TIMEZONE_COMPLETION_ZONE, &zone_value);
- zone = g_value_get_string (&zone_value);
-
- gtk_tree_model_get_value (model, iter, TIMEZONE_COMPLETION_NAME, &name_value);
- name = g_value_get_string (&name_value);
+ gtk_tree_model_get (model, iter,
+ TIMEZONE_COMPLETION_ZONE, &zone,
+ TIMEZONE_COMPLETION_NAME, &name,
+ -1);
if (zone == NULL || zone[0] == 0) {
- GValue lon_value = {0}, lat_value = {0};
const gchar * strlon, * strlat;
gdouble lon = 0.0, lat = 0.0;
- gtk_tree_model_get_value (model, iter, TIMEZONE_COMPLETION_LONGITUDE, &lon_value);
- strlon = g_value_get_string (&lon_value);
+ gtk_tree_model_get (model, iter,
+ TIMEZONE_COMPLETION_LONGITUDE, &strlon,
+ TIMEZONE_COMPLETION_LATITUDE, &strlat,
+ -1);
+
if (strlon != NULL && strlon[0] != 0) {
lon = strtod(strlon, NULL);
}
- gtk_tree_model_get_value (model, iter, TIMEZONE_COMPLETION_LATITUDE, &lat_value);
- strlat = g_value_get_string (&lat_value);
if (strlat != NULL && strlat[0] != 0) {
lat = strtod(strlat, NULL);
}
@@ -125,22 +142,45 @@ timezone_selected (GtkEntryCompletion * widget, GtkTreeModel * model,
GtkListStore * store = GTK_LIST_STORE (g_object_get_data (G_OBJECT (widget), "store"));
GtkTreeIter * store_iter = (GtkTreeIter *)g_object_get_data (G_OBJECT (widget), "store_iter");
if (store != NULL && store_iter != NULL) {
- gtk_list_store_set (store, store_iter, 0, name, 2, zone, -1);
+ gtk_list_store_set (store, store_iter,
+ COL_VISIBLE_NAME, name,
+ COL_ICON, NULL,
+ COL_NAME, name,
+ COL_ZONE, zone, -1);
}
- g_value_unset (&name_value);
- g_value_unset (&zone_value);
+ update_times (dlg);
return FALSE; // Do normal action too
}
+static gboolean
+query_tooltip (GtkTreeView * tree, gint x, gint y, gboolean keyboard_mode,
+ GtkTooltip * tooltip, GtkCellRenderer * cell)
+{
+ GtkTreeModel * model;
+ GtkTreeIter iter;
+ if (!gtk_tree_view_get_tooltip_context (tree, &x, &y, keyboard_mode,
+ &model, NULL, &iter))
+ return FALSE;
+
+ const gchar * icon;
+ gtk_tree_model_get (model, &iter, COL_ICON, &icon, -1);
+ if (icon == NULL)
+ return FALSE;
+
+ GtkTreeViewColumn * col = gtk_tree_view_get_column (tree, 0);
+ gtk_tree_view_set_tooltip_cell (tree, tooltip, NULL, col, cell);
+ gtk_tooltip_set_text (tooltip, _("You need to complete this location for it to appear in the menu."));
+ return TRUE;
+}
+
static void
handle_edit_started (GtkCellRendererText * renderer, GtkCellEditable * editable,
gchar * path, TimezoneCompletion * completion)
{
if (GTK_IS_ENTRY (editable)) {
GtkEntry *entry = GTK_ENTRY (editable);
- gtk_entry_set_completion (entry, GTK_ENTRY_COMPLETION (completion));
timezone_completion_watch_entry (completion, entry);
GtkListStore * store = GTK_LIST_STORE (g_object_get_data (G_OBJECT (completion), "store"));
@@ -152,9 +192,10 @@ handle_edit_started (GtkCellRendererText * renderer, GtkCellEditable * editable,
}
static gboolean
-update_times (TimezoneCompletion * completion)
+update_times (GtkWidget * dlg)
{
/* For each entry, check zone in column 2 and set column 1 to it's time */
+ TimezoneCompletion * completion = TIMEZONE_COMPLETION (g_object_get_data (G_OBJECT (dlg), "completion"));
GtkListStore * store = GTK_LIST_STORE (g_object_get_data (G_OBJECT (completion), "store"));
GObject * cell = G_OBJECT (g_object_get_data (G_OBJECT (completion), "name-cell"));
@@ -164,16 +205,16 @@ update_times (TimezoneCompletion * completion)
return TRUE;
}
+ g_signal_handlers_block_by_func (store, save_when_idle, dlg);
+
GDateTime * now = g_date_time_new_now_local ();
GtkTreeIter iter;
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
do {
- GValue zone_value = {0};
const gchar * strzone;
- gtk_tree_model_get_value (GTK_TREE_MODEL (store), &iter, 2, &zone_value);
- strzone = g_value_get_string (&zone_value);
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, COL_ZONE, &strzone, -1);
if (strzone != NULL && strzone[0] != 0) {
GTimeZone * tz = g_time_zone_new (strzone);
@@ -181,19 +222,20 @@ update_times (TimezoneCompletion * completion)
gchar * format = generate_format_string_at_time (now_tz);
gchar * time_str = g_date_time_format (now_tz, format);
- gtk_list_store_set (store, &iter, 1, time_str, -1);
+ gtk_list_store_set (store, &iter, COL_TIME, time_str, -1);
g_free (time_str);
g_free (format);
g_date_time_unref (now_tz);
g_time_zone_unref (tz);
}
-
- g_value_unset (&zone_value);
} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
}
g_date_time_unref (now);
+
+ g_signal_handlers_unblock_by_func (store, save_when_idle, dlg);
+
return TRUE;
}
@@ -211,7 +253,11 @@ fill_from_settings (GObject * store, GSettings * conf)
split_settings_location (*striter, &zone, &name);
gtk_list_store_append (GTK_LIST_STORE (store), &iter);
- gtk_list_store_set (GTK_LIST_STORE (store), &iter, 0, name, 2, zone, -1);
+ gtk_list_store_set (GTK_LIST_STORE (store), &iter,
+ COL_VISIBLE_NAME, name,
+ COL_ICON, NULL,
+ COL_NAME, name,
+ COL_ZONE, zone, -1);
g_free (zone);
g_free (name);
@@ -221,45 +267,78 @@ fill_from_settings (GObject * store, GSettings * conf)
}
static void
-dialog_closed (GtkWidget * dlg, GObject * store)
+save_to_settings (GObject * store, GSettings * conf)
{
- /* Cleanup a tad */
- guint time_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dlg), "time-id"));
- g_source_remove (time_id);
-
- /* Now save to settings */
+ gboolean empty = TRUE;
GVariantBuilder builder;
g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
GtkTreeIter iter;
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter)) {
do {
- GValue zone_value = {0}, name_value = {0};
const gchar * strzone, * strname;
- gtk_tree_model_get_value (GTK_TREE_MODEL (store), &iter, 0, &name_value);
- gtk_tree_model_get_value (GTK_TREE_MODEL (store), &iter, 2, &zone_value);
-
- strzone = g_value_get_string (&zone_value);
- strname = g_value_get_string (&name_value);
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter,
+ COL_NAME, &strname,
+ COL_ZONE, &strzone,
+ -1);
if (strzone != NULL && strzone[0] != 0 && strname != NULL && strname[0] != 0) {
gchar * settings_string = g_strdup_printf("%s %s", strzone, strname);
g_variant_builder_add (&builder, "s", settings_string);
g_free (settings_string);
+ empty = FALSE;
}
-
- g_value_unset (&zone_value);
- g_value_unset (&name_value);
} while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
}
- GVariant * locations = g_variant_builder_end (&builder);
+ if (empty) {
+ /* Empty list */
+ g_variant_builder_clear (&builder);
+ g_settings_set_strv (conf, SETTINGS_LOCATIONS_S, NULL);
+ }
+ else {
+ GVariant * locations = g_variant_builder_end (&builder);
+ g_settings_set_strv (conf, SETTINGS_LOCATIONS_S, g_variant_get_strv (locations, NULL));
+ g_variant_unref (locations);
+ }
+}
+static gboolean
+save_now (GtkWidget *dlg)
+{
GSettings * conf = G_SETTINGS (g_object_get_data (G_OBJECT (dlg), "conf"));
- g_settings_set_strv (conf, SETTINGS_LOCATIONS_S, g_variant_get_strv (locations, NULL));
+ GObject * completion = G_OBJECT (g_object_get_data (G_OBJECT (dlg), "completion"));
+ GObject * store = G_OBJECT (g_object_get_data (completion, "store"));
+
+ save_to_settings (store, conf);
+
+ g_object_set_data (G_OBJECT (dlg), "save-id", GINT_TO_POINTER(0));
+
+ return FALSE;
+}
+
+static void
+save_when_idle (GtkWidget *dlg)
+{
+ guint save_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dlg), "save-id"));
+
+ if (save_id == 0) {
+ save_id = g_idle_add ((GSourceFunc)save_now, dlg);
+ g_object_set_data (G_OBJECT (dlg), "save-id", GINT_TO_POINTER(save_id));
+ }
+}
- g_variant_unref (locations);
+static void
+dialog_closed (GtkWidget * dlg, GObject * store)
+{
+ /* Cleanup a tad */
+ guint time_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dlg), "time-id"));
+ g_source_remove (time_id);
+
+ guint save_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dlg), "save-id"));
+ if (save_id > 0)
+ g_source_remove (save_id);
}
static void
@@ -270,7 +349,7 @@ selection_changed (GtkTreeSelection * selection, GtkWidget * remove_button)
}
GtkWidget *
-datetime_setup_locations_dialog (GtkWindow * parent, CcTimezoneMap * map)
+datetime_setup_locations_dialog (CcTimezoneMap * map)
{
GError * error = NULL;
GtkBuilder * builder = gtk_builder_new ();
@@ -296,7 +375,7 @@ datetime_setup_locations_dialog (GtkWindow * parent, CcTimezoneMap * map)
TimezoneCompletion * completion = timezone_completion_new ();
g_object_set_data (G_OBJECT (completion), "tzmap", map);
g_object_set_data (G_OBJECT (completion), "store", store);
- g_signal_connect (completion, "match-selected", G_CALLBACK (timezone_selected), NULL);
+ g_signal_connect (completion, "match-selected", G_CALLBACK (timezone_selected), dlg);
GtkCellRenderer * cell = gtk_cell_renderer_text_new ();
g_object_set (cell, "editable", TRUE, NULL);
@@ -304,15 +383,22 @@ datetime_setup_locations_dialog (GtkWindow * parent, CcTimezoneMap * map)
g_signal_connect (cell, "edited", G_CALLBACK (handle_edit), store);
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree), -1,
_("Location"), cell,
- "text", 0, NULL);
+ "text", COL_VISIBLE_NAME, NULL);
GtkTreeViewColumn * loc_col = gtk_tree_view_get_column (GTK_TREE_VIEW (tree), 0);
gtk_tree_view_column_set_expand (loc_col, TRUE);
g_object_set_data (G_OBJECT (completion), "name-cell", cell);
+ cell = gtk_cell_renderer_pixbuf_new ();
+ gtk_tree_view_column_pack_start (loc_col, cell, FALSE);
+ gtk_tree_view_column_add_attribute (loc_col, cell, "icon-name", COL_ICON);
+
+ gtk_widget_set_has_tooltip (tree, TRUE);
+ g_signal_connect (tree, "query-tooltip", G_CALLBACK (query_tooltip), cell);
+
cell = gtk_cell_renderer_text_new ();
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree), -1,
_("Time"), cell,
- "text", 1, NULL);
+ "text", COL_TIME, NULL);
GtkTreeSelection * selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree));
gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
@@ -323,16 +409,18 @@ datetime_setup_locations_dialog (GtkWindow * parent, CcTimezoneMap * map)
g_signal_connect (WIG ("removeButton"), "clicked", G_CALLBACK (handle_remove), tree);
fill_from_settings (store, conf);
-
- guint time_id = g_timeout_add_seconds (2, (GSourceFunc)update_times, completion);
- update_times (completion);
+ g_signal_connect_swapped (store, "row-deleted", G_CALLBACK (save_when_idle), dlg);
+ g_signal_connect_swapped (store, "row-inserted", G_CALLBACK (save_when_idle), dlg);
+ g_signal_connect_swapped (store, "row-changed", G_CALLBACK (save_when_idle), dlg);
+ g_signal_connect_swapped (store, "rows-reordered", G_CALLBACK (save_when_idle), dlg);
g_object_set_data_full (G_OBJECT (dlg), "conf", g_object_ref (conf), g_object_unref);
g_object_set_data_full (G_OBJECT (dlg), "completion", completion, g_object_unref);
- g_object_set_data (G_OBJECT (dlg), "time-id", GINT_TO_POINTER(time_id));
g_signal_connect (dlg, "destroy", G_CALLBACK (dialog_closed), store);
- gtk_window_set_transient_for (GTK_WINDOW (dlg), parent);
+ guint time_id = g_timeout_add_seconds (2, (GSourceFunc)update_times, dlg);
+ g_object_set_data (G_OBJECT (dlg), "time-id", GINT_TO_POINTER(time_id));
+ update_times (dlg);
#undef WIG
diff --git a/src/datetime-prefs-locations.h b/src/datetime-prefs-locations.h
index 1760567..e312894 100644
--- a/src/datetime-prefs-locations.h
+++ b/src/datetime-prefs-locations.h
@@ -28,7 +28,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
G_BEGIN_DECLS
-GtkWidget * datetime_setup_locations_dialog (GtkWindow * parent, CcTimezoneMap * map);
+GtkWidget * datetime_setup_locations_dialog (CcTimezoneMap * map);
G_END_DECLS
diff --git a/src/datetime-prefs.c b/src/datetime-prefs.c
index fbc88f2..4a32fd6 100644
--- a/src/datetime-prefs.c
+++ b/src/datetime-prefs.c
@@ -53,6 +53,7 @@ GtkWidget * date_spin = NULL;
guint save_time_id = 0;
gboolean user_edited_time = FALSE;
gboolean changing_time = FALSE;
+GtkWidget * loc_dlg = NULL;
/* Turns the boolean property into a string gsettings */
static GVariant *
@@ -180,13 +181,50 @@ ntp_query_answered (GObject *object, GAsyncResult *res, gpointer user_data)
g_variant_unref (answers);
}
+static gchar *
+get_zone_name (const gchar * location)
+{
+ gchar * new_zone, * new_name;
+ gchar * old_zone, * old_name;
+ gchar * rv;
+
+ split_settings_location (location, &new_zone, &new_name);
+
+ GSettings * conf = g_settings_new (SETTINGS_INTERFACE);
+ gchar * tz_name = g_settings_get_string (conf, SETTINGS_TIMEZONE_NAME_S);
+ split_settings_location (tz_name, &old_zone, &old_name);
+ g_free (tz_name);
+ g_object_unref (conf);
+
+ // new_name is always just a sanitized version of a timezone.
+ // old_name is potentially a saved "pretty" version of a timezone name from
+ // geonames. So we prefer to use it if available and the zones match.
+
+ if (g_strcmp0 (old_zone, new_zone) == 0) {
+ rv = old_name;
+ old_name = NULL;
+ }
+ else {
+ rv = new_name;
+ new_name = NULL;
+ }
+
+ g_free (new_zone);
+ g_free (old_zone);
+ g_free (new_name);
+ g_free (old_name);
+
+ return rv;
+}
+
static void
sync_entry (const gchar * location)
{
- gchar * name;
- split_settings_location (location, NULL, &name);
+ gchar * name = get_zone_name (location);
gtk_entry_set_text (GTK_ENTRY (tz_entry), name);
g_free (name);
+
+ gtk_entry_set_icon_from_stock (GTK_ENTRY (tz_entry), GTK_ENTRY_ICON_SECONDARY, NULL);
}
static void
@@ -495,51 +533,92 @@ setup_time_spinners (GtkWidget * time, GtkWidget * date)
}
static void
+hide_locations ()
+{
+ if (loc_dlg != NULL)
+ gtk_widget_destroy (loc_dlg);
+}
+
+static void
show_locations (GtkWidget * button, GtkWidget * dlg)
{
- GtkWidget * locationsDlg = datetime_setup_locations_dialog (GTK_WINDOW (dlg), tzmap);
- gtk_widget_show_all (locationsDlg);
+ if (loc_dlg == NULL) {
+ loc_dlg = datetime_setup_locations_dialog (tzmap);
+ gtk_window_set_transient_for (GTK_WINDOW (loc_dlg), GTK_WINDOW (dlg));
+ g_signal_connect (loc_dlg, "destroy", G_CALLBACK (gtk_widget_destroyed), &loc_dlg);
+ g_signal_connect (dlg, "focus-in-event", G_CALLBACK (hide_locations), NULL);
+ gtk_widget_show_all (loc_dlg);
+ }
+ else {
+ gtk_window_present_with_time (GTK_WINDOW (loc_dlg), gtk_get_current_event_time ());
+ }
}
static gboolean
timezone_selected (GtkEntryCompletion * widget, GtkTreeModel * model,
GtkTreeIter * iter, gpointer user_data)
{
- GValue value = {0};
- const gchar * strval;
+ const gchar * name, * zone;
- gtk_tree_model_get_value (model, iter, TIMEZONE_COMPLETION_ZONE, &value);
- strval = g_value_get_string (&value);
+ gtk_tree_model_get (model, iter,
+ TIMEZONE_COMPLETION_NAME, &name,
+ TIMEZONE_COMPLETION_ZONE, &zone,
+ -1);
- if (strval != NULL && strval[0] != 0) {
- cc_timezone_map_set_timezone (tzmap, strval);
- }
- else {
- GValue lon_value = {0}, lat_value = {0};
+ if (zone == NULL || zone[0] == 0) {
const gchar * strlon, * strlat;
gdouble lon = 0.0, lat = 0.0;
- gtk_tree_model_get_value (model, iter, TIMEZONE_COMPLETION_LONGITUDE, &lon_value);
- strlon = g_value_get_string (&lon_value);
+ gtk_tree_model_get (model, iter,
+ TIMEZONE_COMPLETION_LONGITUDE, &strlon,
+ TIMEZONE_COMPLETION_LATITUDE, &strlat,
+ -1);
+
if (strlon != NULL && strlon[0] != 0) {
lon = strtod(strlon, NULL);
}
- gtk_tree_model_get_value (model, iter, TIMEZONE_COMPLETION_LATITUDE, &lat_value);
- strlat = g_value_get_string (&lat_value);
if (strlat != NULL && strlat[0] != 0) {
lat = strtod(strlat, NULL);
}
- cc_timezone_map_set_coords (tzmap, lon, lat);
+ zone = cc_timezone_map_get_timezone_at_coords (tzmap, lon, lat);
}
- g_value_unset (&value);
+ GSettings * conf = g_settings_new (SETTINGS_INTERFACE);
+ gchar * tz_name = g_strdup_printf ("%s %s", zone, name);
+ g_settings_set_string (conf, SETTINGS_TIMEZONE_NAME_S, tz_name);
+ g_free (tz_name);
+ g_object_unref (conf);
+
+ cc_timezone_map_set_timezone (tzmap, zone);
return FALSE; // Do normal action too
}
static gboolean
+entry_focus_out (GtkEntry * entry, GdkEventFocus * event)
+{
+ // If the name left in the entry doesn't match the current timezone name,
+ // show an error icon. It's always an error for the user to manually type in
+ // a timezone.
+ TzLocation * location = cc_timezone_map_get_location (tzmap);
+ if (location == NULL)
+ return FALSE;
+
+ gchar * name = get_zone_name (location->zone);
+ gboolean correct = (g_strcmp0 (gtk_entry_get_text (entry), name) == 0);
+ g_free (name);
+
+ gtk_entry_set_icon_from_stock (entry, GTK_ENTRY_ICON_SECONDARY,
+ correct ? NULL : GTK_STOCK_DIALOG_ERROR);
+ gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY,
+ _("You need to choose a location to change the time zone."));
+ gtk_entry_set_icon_activatable (entry, GTK_ENTRY_ICON_SECONDARY, FALSE);
+ return FALSE;
+}
+
+static gboolean
key_pressed (GtkWidget * widget, GdkEventKey * event, gpointer user_data)
{
switch (event->keyval) {
@@ -604,10 +683,9 @@ create_dialog (void)
/* And completion entry */
TimezoneCompletion * completion = timezone_completion_new ();
- gtk_entry_set_completion (GTK_ENTRY (WIG ("timezoneEntry")),
- GTK_ENTRY_COMPLETION (completion));
timezone_completion_watch_entry (completion, GTK_ENTRY (WIG ("timezoneEntry")));
g_signal_connect (completion, "match-selected", G_CALLBACK (timezone_selected), NULL);
+ g_signal_connect (WIG ("timezoneEntry"), "focus-out-event", G_CALLBACK (entry_focus_out), NULL);
/* Set up settings bindings */
g_settings_bind (conf, SETTINGS_SHOW_CLOCK_S, WIG ("showClockCheck"),
diff --git a/src/datetime-service.c b/src/datetime-service.c
index 65df77e..1ddaa4d 100644
--- a/src/datetime-service.c
+++ b/src/datetime-service.c
@@ -276,22 +276,70 @@ activate_cb (DbusmenuMenuitem * menuitem, guint timestamp, const gchar *command)
}
static gboolean
+update_appointment_menu_items_idle (gpointer user_data)
+{
+ update_appointment_menu_items(user_data);
+ return FALSE;
+}
+
+static gboolean
month_changed_cb (DbusmenuMenuitem * menuitem, gchar *name, GVariant *variant, guint timestamp)
{
start_time_appointments = (time_t)g_variant_get_uint32(variant);
g_debug("Received month changed with timestamp: %d -> %s",(int)start_time_appointments, ctime(&start_time_appointments));
- update_appointment_menu_items(NULL);
+ /* By default one of the first things we do is
+ clear the marks as we don't know the correct
+ ones yet and we don't want to confuse the
+ user. */
+ dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
+
+ GList * appointment;
+ for (appointment = appointments; appointment != NULL; appointment = g_list_next(appointment)) {
+ DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(appointment->data);
+ dbusmenu_menuitem_property_set_bool(mi, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ }
+
+ g_idle_add(update_appointment_menu_items_idle, NULL);
return TRUE;
}
static gboolean
day_selected_cb (DbusmenuMenuitem * menuitem, gchar *name, GVariant *variant, guint timestamp)
{
- start_time_appointments = (time_t)g_variant_get_uint32(variant);
-
+ time_t new_time = (time_t)g_variant_get_uint32(variant);
+ g_warn_if_fail(new_time != 0);
+
+ if (start_time_appointments == 0 || new_time == 0) {
+ /* If we've got nothing, assume everyhting is going to
+ get repopulated, let's start with a clean slate */
+ dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
+ } else {
+ /* No check to see if we changed months. If we did we'll
+ want to clear the marks. Otherwise we're cool keeping
+ them around. */
+ struct tm start_tm;
+ struct tm new_tm;
+
+ localtime_r(&start_time_appointments, &start_tm);
+ localtime_r(&new_time, &new_tm);
+
+ if (start_tm.tm_mon != new_tm.tm_mon) {
+ dbusmenu_menuitem_property_remove(menuitem, CALENDAR_MENUITEM_PROP_MARKS);
+ }
+ }
+
+ GList * appointment;
+ for (appointment = appointments; appointment != NULL; appointment = g_list_next(appointment)) {
+ DbusmenuMenuitem * mi = DBUSMENU_MENUITEM(appointment->data);
+ dbusmenu_menuitem_property_set_bool(mi, DBUSMENU_MENUITEM_PROP_ENABLED, FALSE);
+ }
+
+ start_time_appointments = new_time;
+
g_debug("Received day-selected with timestamp: %d -> %s",(int)start_time_appointments, ctime(&start_time_appointments));
- update_appointment_menu_items(NULL);
+ g_idle_add(update_appointment_menu_items_idle, NULL);
+
return TRUE;
}
@@ -316,6 +364,28 @@ day_selected_double_click_cb (DbusmenuMenuitem * menuitem, gchar *name, GVariant
return TRUE;
}
+static gboolean
+close_menu_cb (DbusmenuMenuitem * menuitem, gchar *name, GVariant *variant)
+{
+ if (calendar == NULL) return FALSE;
+ g_debug("Resetting date on menu close");
+ start_time_appointments = 0;
+ // TODO create a variant which will be an array of 3 ints {y,m,d}
+ GVariant *date_variant;
+ time_t curtime;
+ struct tm *t1;
+ time(&curtime);
+ t1 = localtime(&curtime);
+ GVariant *date[3];
+ date[0] = g_variant_new_uint32(t1->tm_year + 1900);
+ date[1] = g_variant_new_uint32(t1->tm_mon);
+ date[2] = g_variant_new_uint32(t1->tm_mday);
+ date_variant = g_variant_new_array(NULL, date, 3);
+
+ dbusmenu_menuitem_property_set_variant (calendar, CALENDAR_MENUITEM_PROP_SET_DATE, date_variant);
+ return TRUE;
+}
+
static guint ecaltimer = 0;
static void
@@ -331,6 +401,12 @@ stop_ecal_timer(void)
{
if (ecaltimer != 0) g_source_remove(ecaltimer);
}
+static gboolean
+idle_start_ecal_timer (gpointer data)
+{
+ start_ecal_timer();
+ return FALSE;
+}
static void
show_events_changed (void)
@@ -344,14 +420,13 @@ show_events_changed (void)
dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
/* Remove all of the previous appointments */
if (appointments != NULL) {
- g_debug("Freeing old appointments");
- while (appointments != NULL) {
- DbusmenuMenuitem * litem = DBUSMENU_MENUITEM(appointments->data);
- g_debug("Freeing old appointment: %p", litem);
+ g_debug("Hiding old appointments");
+ GList * appointment;
+ for (appointment = appointments; appointment != NULL; appointment = g_list_next(appointment)) {
+ DbusmenuMenuitem * litem = DBUSMENU_MENUITEM(appointment->data);
+ g_debug("Hiding old appointment: %p", litem);
// Remove all the existing menu items which are in appointments.
- appointments = g_list_remove(appointments, litem);
- dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(litem));
- g_object_unref(G_OBJECT(litem));
+ dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(litem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
}
}
stop_ecal_timer();
@@ -364,12 +439,13 @@ static gboolean
check_for_calendar (gpointer user_data)
{
g_return_val_if_fail (calendar != NULL, FALSE);
-
+ // Always enable the calendar even if it does nothing
+ dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+ dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+
gchar *evo = g_find_program_in_path("evolution");
if (evo != NULL) {
g_debug("Found the calendar application: %s", evo);
- dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- dbusmenu_menuitem_property_set_bool(calendar, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
dbusmenu_menuitem_property_set_bool(date, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
g_signal_connect (G_OBJECT(date), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED,
@@ -388,7 +464,7 @@ check_for_calendar (gpointer user_data)
if (g_settings_get_boolean(conf, SETTINGS_SHOW_EVENTS_S)) {
dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
- start_ecal_timer();
+ g_idle_add((GSourceFunc)idle_start_ecal_timer, NULL);
} else {
dbusmenu_menuitem_property_set_bool(add_appointment, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
dbusmenu_menuitem_property_set_bool(events_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
@@ -437,11 +513,11 @@ update_timezone_menu_items(gpointer user_data) {
gboolean show = g_settings_get_boolean (conf, SETTINGS_SHOW_LOCATIONS_S);
- if (len > 0) {
- dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, show);
- dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, show);
- dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
- } else {
+ dbusmenu_menuitem_property_set_bool (locations_separator, DBUSMENU_MENUITEM_PROP_VISIBLE, show);
+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_VISIBLE, show);
+ dbusmenu_menuitem_property_set_bool (current_location, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
+
+ if (len == 0) {
g_debug("No locations configured (Empty List)");
return FALSE;
}
@@ -579,7 +655,7 @@ update_appointment_menu_items (gpointer user_data)
const int mday = today->tm_mday;
const int mon = today->tm_mon;
const int year = today->tm_year;
-
+
struct tm *start_tm = NULL;
int this_year = today->tm_year + 1900;
int days[12]={31,28,31,30,31,30,31,31,30,31,30,31};
@@ -599,16 +675,13 @@ update_appointment_menu_items (gpointer user_data)
month_start.tm_mon = start_tm->tm_mon;
month_start.tm_mday = 1;
t1 = mktime(&month_start);
- highlightdays = days[mon];
+ highlightdays = days[start_month];
}
}
g_debug("Will highlight %d days from %s", highlightdays, ctime(&t1));
- t2 = t1 + (time_t) (highlightdays * 24 * 60 * 60);
-
- // Remove all highlights from the calendar widget
- dbusmenu_menuitem_property_set (calendar, CALENDAR_MENUITEM_PROP_CLEAR_MARKS, NULL);
+ t2 = t1 + (time_t) (highlightdays * 24 * 60 * 60);
if (!e_cal_get_sources(&sources, E_CAL_SOURCE_TYPE_EVENT, &gerror)) {
g_debug("Failed to get ecal sources\n");
@@ -652,16 +725,15 @@ update_appointment_menu_items (gpointer user_data)
comp_instances = NULL;
g_debug("Components sorted");
- /* Remove all of the previous appointments */
+ /* Hiding all of the previous appointments */
if (appointments != NULL) {
- g_debug("Freeing old appointments");
- while (appointments != NULL) {
- DbusmenuMenuitem * litem = DBUSMENU_MENUITEM(appointments->data);
- g_debug("Freeing old appointment: %p", litem);
+ g_debug("Hiding old appointments");
+ GList * appointment;
+ for (appointment = appointments; appointment != NULL; appointment = g_list_next(appointment)) {
+ DbusmenuMenuitem * litem = DBUSMENU_MENUITEM(appointment->data);
+ g_debug("Hiding old appointment: %p", litem);
// Remove all the existing menu items which are in appointments.
- appointments = g_list_remove(appointments, litem);
- dbusmenu_menuitem_child_delete(root, DBUSMENU_MENUITEM(litem));
- g_object_unref(G_OBJECT(litem));
+ dbusmenu_menuitem_property_set_bool(DBUSMENU_MENUITEM(litem), DBUSMENU_MENUITEM_PROP_VISIBLE, FALSE);
}
}
@@ -678,10 +750,18 @@ update_appointment_menu_items (gpointer user_data)
} else if (g_strcmp0(time_format_str, "24-hour") == 0) {
apt_output = SETTINGS_TIME_24_HOUR;
} else {
- apt_output = SETTINGS_TIME_LOCALE;
+ if (is_locale_12h()) {
+ apt_output = SETTINGS_TIME_12_HOUR;
+ } else {
+ apt_output = SETTINGS_TIME_24_HOUR;
+ }
}
+ GVariantBuilder markeddays;
+ g_variant_builder_init (&markeddays, G_VARIANT_TYPE_ARRAY);
+
i = 0;
+ GList * cached_appointment = appointments;
for (l = sorted_comp_instances; l; l = l->next) {
struct comp_instance *ci = l->data;
ECalComponent *ecalcomp = ci->comp;
@@ -702,9 +782,8 @@ update_appointment_menu_items (gpointer user_data)
const int dyear = due->tm_year;
// Mark day
- g_debug("Marking date %s", ctime(&ci->start));
- dbusmenu_menuitem_property_set_int (calendar, CALENDAR_MENUITEM_PROP_MARK, due->tm_mday);
-
+ g_debug("Adding marked date %s, %d", ctime(&ci->start), dmday);
+ g_variant_builder_add (&markeddays, "i", dmday);
// If the appointment time is less than the selected date,
// don't create an appointment item for it.
@@ -717,12 +796,28 @@ update_appointment_menu_items (gpointer user_data)
if (i >= 5) continue;
i++;
- g_debug("Create menu item");
-
- item = dbusmenu_menuitem_new();
- dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, APPOINTMENT_MENUITEM_TYPE);
+ if (cached_appointment == NULL) {
+ g_debug("Create menu item");
+
+ item = dbusmenu_menuitem_new();
+ dbusmenu_menuitem_property_set (item, DBUSMENU_MENUITEM_PROP_TYPE, APPOINTMENT_MENUITEM_TYPE);
+
+ dbusmenu_menuitem_child_add_position (root, item, 2+i);
+ appointments = g_list_append (appointments, item); // Keep track of the items here to make them easy to remove
+ } else {
+ item = DBUSMENU_MENUITEM(cached_appointment->data);
+ cached_appointment = g_list_next(cached_appointment);
+
+ /* Remove the icon as we might not replace it on error */
+ dbusmenu_menuitem_property_remove(item, APPOINTMENT_MENUITEM_PROP_ICON);
+
+ /* Remove the activate handler */
+ g_signal_handlers_disconnect_matched(G_OBJECT(item), G_SIGNAL_MATCH_FUNC, 0, 0, NULL, G_CALLBACK(activate_cb), NULL);
+ }
+
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_ENABLED, TRUE);
dbusmenu_menuitem_property_set_bool (item, DBUSMENU_MENUITEM_PROP_VISIBLE, TRUE);
+
// Label text
e_cal_component_get_summary (ecalcomp, &valuetext);
@@ -743,11 +838,6 @@ update_appointment_menu_items (gpointer user_data)
strftime(right, 20, _(DEFAULT_TIME_24_FORMAT), due);
else
strftime(right, 20, _(DEFAULT_TIME_24_FORMAT_WITH_DAY), due);
- } else {
- if ((mday == dmday) && (mon == dmon) && (year == dyear))
- strftime(right, 20, _(DEFAULT_TIME_FORMAT), due);
- else
- strftime(right, 20, _(DEFAULT_TIME_FORMAT_WITH_DAY), due);
}
g_debug("Appointment time: %s, for date %s", right, asctime(due));
dbusmenu_menuitem_property_set (item, APPOINTMENT_MENUITEM_PROP_RIGHT, right);
@@ -820,8 +910,6 @@ update_appointment_menu_items (gpointer user_data)
cairo_surface_destroy (surface);
cairo_destroy(cr);
}
- dbusmenu_menuitem_child_add_position (root, item, 2+i);
- appointments = g_list_append (appointments, item); // Keep track of the items here to make them easy to remove
g_debug("Adding appointment: %p", item);
}
@@ -832,6 +920,9 @@ update_appointment_menu_items (gpointer user_data)
}
g_list_free(sorted_comp_instances);
+ GVariant * marks = g_variant_builder_end (&markeddays);
+ dbusmenu_menuitem_property_set_variant (calendar, CALENDAR_MENUITEM_PROP_MARKS, marks);
+
updating_appointments = FALSE;
g_debug("End of objects");
return TRUE;
@@ -1218,6 +1309,9 @@ main (int argc, char ** argv)
build_menus(root);
+ // Connect to the close signal to reset the calendar date
+ g_signal_connect(root, "event::closed", G_CALLBACK(close_menu_cb), NULL);
+
/* Cache the timezone */
update_current_timezone();
diff --git a/src/dbus-shared.h b/src/dbus-shared.h
index 8b1a20b..51632f9 100644
--- a/src/dbus-shared.h
+++ b/src/dbus-shared.h
@@ -31,9 +31,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
// The following properties are not *really* properties, but are just
// a way of accessing the calendar from the service
-#define CALENDAR_MENUITEM_PROP_MARK "calendar-mark"
-#define CALENDAR_MENUITEM_PROP_UNMARK "calendar-unmark"
-#define CALENDAR_MENUITEM_PROP_CLEAR_MARKS "calendar-clear-marks"
+#define CALENDAR_MENUITEM_PROP_MARKS "calendar-marks"
#define CALENDAR_MENUITEM_PROP_SET_DATE "calendar-set-date"
diff --git a/src/indicator-datetime.c b/src/indicator-datetime.c
index 1cdcd3f..a999f42 100644
--- a/src/indicator-datetime.c
+++ b/src/indicator-datetime.c
@@ -101,6 +101,8 @@ struct _IndicatorDatetimePrivate {
GList * timezone_items;
GSettings * settings;
+
+ GtkSizeGroup * indicator_right_group;
};
/* Enum for the properties so that they can be quickly
@@ -169,10 +171,15 @@ static void update_label (IndicatorDatetime * io, GDateTime **
static void guess_label_size (IndicatorDatetime * self);
static void setup_timer (IndicatorDatetime * self, GDateTime * datetime);
static void update_time (IndicatorDatetime * self);
+static void session_active_change_cb (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data);
static void receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name, GVariant * parameters, gpointer user_data);
+static void system_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data);
static void service_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data);
static gint generate_strftime_bitmask (const char *time_str);
static void timezone_update_labels (indicator_item_t * mi_data);
+static gboolean new_calendar_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
+static gboolean new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
+static gboolean new_timezone_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, DbusmenuClient * client, gpointer user_data);
/* Indicator Module Config */
INDICATOR_SET_VERSION
@@ -180,8 +187,6 @@ INDICATOR_SET_TYPE(INDICATOR_DATETIME_TYPE)
G_DEFINE_TYPE (IndicatorDatetime, indicator_datetime, INDICATOR_OBJECT_TYPE);
-static GtkSizeGroup * indicator_right_group = NULL;
-
static void
indicator_datetime_class_init (IndicatorDatetimeClass *klass)
{
@@ -339,6 +344,14 @@ indicator_datetime_init (IndicatorDatetime *self)
}
self->priv->sm = indicator_service_manager_new_version(SERVICE_NAME, SERVICE_VERSION);
+ self->priv->indicator_right_group = GTK_SIZE_GROUP(gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL));
+
+ self->priv->menu = dbusmenu_gtkmenu_new(SERVICE_NAME, MENU_OBJ);
+
+ DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(self->priv->menu);
+ dbusmenu_client_add_type_handler_full(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item, self, NULL);
+ dbusmenu_client_add_type_handler_full(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item, self, NULL);
+ dbusmenu_client_add_type_handler_full(DBUSMENU_CLIENT(client), TIMEZONE_MENUITEM_TYPE, new_timezone_item, self, NULL);
self->priv->service_proxy_cancel = g_cancellable_new();
@@ -352,8 +365,34 @@ indicator_datetime_init (IndicatorDatetime *self)
service_proxy_cb,
self);
+ g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.ConsoleKit",
+ "/org/freedesktop/ConsoleKit/Manager",
+ "org.freedesktop.ConsoleKit.Manager",
+ NULL, system_proxy_cb, self);
return;
}
+/* for hooking into console kit signal on wake from suspend */
+static void
+system_proxy_cb (GObject * object, GAsyncResult * res, gpointer user_data)
+{
+ GError * error = NULL;
+
+ IndicatorDatetime * self = INDICATOR_DATETIME(user_data);
+ g_return_if_fail(self != NULL);
+
+ GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
+
+ if (error != NULL) {
+ g_warning("Could not grab DBus proxy for %s: %s", SERVICE_NAME, error->message);
+ g_error_free(error);
+ return;
+ }
+ g_signal_connect(proxy, "g-signal", G_CALLBACK(session_active_change_cb), self);
+
+}
/* Callback from trying to create the proxy for the serivce, this
could include starting the service. Sometime it'll fail and
@@ -430,6 +469,11 @@ indicator_datetime_dispose (GObject *object)
self->priv->service_proxy = NULL;
}
+ if (self->priv->indicator_right_group != NULL) {
+ g_object_unref(G_OBJECT(self->priv->indicator_right_group));
+ self->priv->indicator_right_group = NULL;
+ }
+
G_OBJECT_CLASS (indicator_datetime_parent_class)->dispose (object);
return;
}
@@ -512,7 +556,9 @@ set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec
case PROP_SHOW_CLOCK: {
if (g_value_get_boolean(value) != self->priv->show_clock) {
self->priv->show_clock = g_value_get_boolean(value);
- gtk_widget_set_visible (GTK_WIDGET (self->priv->label), self->priv->show_clock);
+ if (self->priv->label != NULL) {
+ gtk_widget_set_visible (GTK_WIDGET (self->priv->label), self->priv->show_clock);
+ }
}
break;
}
@@ -525,7 +571,7 @@ set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec
}
break;
}
- case PROP_SHOW_SECONDS:
+ case PROP_SHOW_SECONDS: {
if (g_value_get_boolean(value) != self->priv->show_seconds) {
self->priv->show_seconds = !self->priv->show_seconds;
if (self->priv->time_mode != SETTINGS_TIME_CUSTOM) {
@@ -534,7 +580,8 @@ set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec
}
}
break;
- case PROP_SHOW_DAY:
+ }
+ case PROP_SHOW_DAY: {
if (g_value_get_boolean(value) != self->priv->show_day) {
self->priv->show_day = !self->priv->show_day;
if (self->priv->time_mode != SETTINGS_TIME_CUSTOM) {
@@ -542,7 +589,8 @@ set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec
}
}
break;
- case PROP_SHOW_DATE:
+ }
+ case PROP_SHOW_DATE: {
if (g_value_get_boolean(value) != self->priv->show_date) {
self->priv->show_date = !self->priv->show_date;
if (self->priv->time_mode != SETTINGS_TIME_CUSTOM) {
@@ -550,6 +598,7 @@ set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec
}
}
break;
+ }
case PROP_CUSTOM_TIME_FORMAT: {
const gchar * newstr = g_value_get_string(value);
if (g_strcmp0(newstr, self->priv->custom_string) != 0) {
@@ -582,14 +631,17 @@ set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec
case PROP_SHOW_CALENDAR: {
if (g_value_get_boolean(value) != self->priv->show_calendar) {
self->priv->show_calendar = g_value_get_boolean(value);
- gtk_widget_set_visible (GTK_WIDGET (self->priv->ido_calendar), self->priv->show_calendar);
+ if (self->priv->ido_calendar != NULL) {
+ gtk_widget_set_visible (GTK_WIDGET (self->priv->ido_calendar), self->priv->show_calendar);
+ }
}
break;
- }
- default:
+ }
+ default: {
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
return;
}
+ }
if (!update) {
return;
@@ -772,6 +824,18 @@ update_time (IndicatorDatetime * self)
return;
}
+static void
+session_active_change_cb (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name,
+ GVariant * parameters, gpointer user_data)
+{
+ // Just returned from suspend
+ IndicatorDatetime * self = INDICATOR_DATETIME(user_data);
+ if (g_strcmp0(signal_name, "SystemIdleHintChanged") == 0 && g_variant_get_boolean(parameters) == FALSE) {
+ update_time(self);
+ }
+ return;
+}
+
/* Receives all signals from the service, routed to the appropriate functions */
static void
receive_signal (GDBusProxy * proxy, gchar * sender_name, gchar * signal_name,
@@ -813,7 +877,7 @@ setup_timer (IndicatorDatetime * self, GDateTime * datetime)
if (self->priv->show_seconds ||
(self->priv->time_mode == SETTINGS_TIME_CUSTOM && self->priv->custom_show_seconds)) {
- self->priv->timer = g_timeout_add_full(G_PRIORITY_HIGH, 865, timer_func, self, NULL);
+ self->priv->timer = g_timeout_add_full(G_PRIORITY_HIGH, 999, timer_func, self, NULL);
} else {
if (datetime == NULL) {
datetime = g_date_time_new_now_local();
@@ -1144,21 +1208,38 @@ indicator_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant *value,
timezone_update_labels(mi_data);
} else if (!g_strcmp0(prop, TIMEZONE_MENUITEM_PROP_RADIO)) {
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(mi_data->gmi), g_variant_get_boolean(value));
-
- // Properties for marking and unmarking the calendar
-
- } else if (!g_strcmp0(prop, CALENDAR_MENUITEM_PROP_MARK)) {
- ido_calendar_menu_item_mark_day (IDO_CALENDAR_MENU_ITEM (mi_data), g_variant_get_int16(value));
- } else if (!g_strcmp0(prop, CALENDAR_MENUITEM_PROP_UNMARK)) {
- ido_calendar_menu_item_unmark_day (IDO_CALENDAR_MENU_ITEM (mi_data), g_variant_get_int16(value));
- } else if (!g_strcmp0(prop, CALENDAR_MENUITEM_PROP_CLEAR_MARKS)) {
+ }
+ return;
+}
+// Properties for marking and unmarking the calendar
+static void
+calendar_prop_change_cb (DbusmenuMenuitem * mi, gchar * prop, GVariant *value, IdoCalendarMenuItem * mi_data)
+{
+ g_debug("Changing calendar property: %s", prop);
+ if (!g_strcmp0(prop, CALENDAR_MENUITEM_PROP_MARKS)) {
ido_calendar_menu_item_clear_marks (IDO_CALENDAR_MENU_ITEM (mi_data));
+
+ if (value != NULL) {
+ GVariantIter *iter;
+ gint day;
+
+ g_debug("\tMarks: %s", g_variant_print(value, FALSE));
+
+ g_variant_get (value, "ai", &iter);
+ while (g_variant_iter_loop (iter, "i", &day)) {
+ ido_calendar_menu_item_mark_day (IDO_CALENDAR_MENU_ITEM (mi_data), day);
+ }
+ g_variant_iter_free (iter);
+ } else {
+ g_debug("\tMarks: <cleared>");
+ }
} else if (!g_strcmp0(prop, CALENDAR_MENUITEM_PROP_SET_DATE)) {
- gsize size = 3;
- const gint * array = g_variant_get_fixed_array(value, &size, sizeof(gint));
- ido_calendar_menu_item_set_date (IDO_CALENDAR_MENU_ITEM (mi_data), array[0], array[1], array[2]);
- } else {
- g_warning("Indicator Item property '%s' unknown", prop);
+ if (value != NULL) {
+ gsize size = 3;
+ const gint * array = g_variant_get_fixed_array(value, &size, sizeof(gint));
+ g_debug("Setting date y-m-d: %d-%d-%d", array[0], array[1], array[2]);
+ ido_calendar_menu_item_set_date (IDO_CALENDAR_MENU_ITEM (mi_data), array[0], array[1], array[2]);
+ }
}
return;
}
@@ -1174,7 +1255,9 @@ new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu
{
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+ g_return_val_if_fail(IS_INDICATOR_DATETIME(user_data), FALSE);
/* Note: not checking parent, it's reasonable for it to be NULL */
+ IndicatorDatetime * self = INDICATOR_DATETIME(user_data);
indicator_item_t * mi_data = g_new0(indicator_item_t, 1);
@@ -1224,7 +1307,7 @@ new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu
/* Usually either the time or the count on the individual
item. */
mi_data->right = gtk_label_new(dbusmenu_menuitem_property_get(newitem, APPOINTMENT_MENUITEM_PROP_RIGHT));
- gtk_size_group_add_widget(indicator_right_group, mi_data->right);
+ gtk_size_group_add_widget(self->priv->indicator_right_group, mi_data->right);
gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, 0);
gtk_widget_show(mi_data->right);
@@ -1235,8 +1318,6 @@ new_appointment_item (DbusmenuMenuitem * newitem, DbusmenuMenuitem * parent, Dbu
dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(mi_data->gmi), parent);
g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(indicator_prop_change_cb), mi_data);
- g_signal_connect_swapped(G_OBJECT(newitem), "destroyed", G_CALLBACK(g_free), mi_data);
-
return TRUE;
}
@@ -1300,17 +1381,13 @@ new_calendar_item (DbusmenuMenuitem * newitem,
DbusmenuClient * client,
gpointer user_data)
{
+ g_debug("New calendar item");
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+ g_return_val_if_fail(IS_INDICATOR_DATETIME(user_data), FALSE);
/* Note: not checking parent, it's reasonable for it to be NULL */
- IndicatorObject *io = g_object_get_data (G_OBJECT (client), "indicator");
- if (io == NULL) {
- g_warning ("found no indicator to attach the caledar to");
- return FALSE;
- }
-
- IndicatorDatetime *self = INDICATOR_DATETIME(io);
+ IndicatorDatetime *self = INDICATOR_DATETIME(user_data);
self->priv = INDICATOR_DATETIME_GET_PRIVATE(self);
IdoCalendarMenuItem *ido = IDO_CALENDAR_MENU_ITEM (ido_calendar_menu_item_new ());
@@ -1326,10 +1403,26 @@ new_calendar_item (DbusmenuMenuitem * newitem,
gtk_widget_set_visible (GTK_WIDGET (self->priv->ido_calendar), self->priv->show_calendar);
dbusmenu_gtkclient_newitem_base(DBUSMENU_GTKCLIENT(client), newitem, GTK_MENU_ITEM(ido), parent);
+
g_signal_connect_after(ido, "month-changed", G_CALLBACK(month_changed_cb), (gpointer)newitem);
g_signal_connect_after(ido, "day-selected", G_CALLBACK(day_selected_cb), (gpointer)newitem);
g_signal_connect_after(ido, "day-selected-double-click", G_CALLBACK(day_selected_double_click_cb), (gpointer)newitem);
+ g_signal_connect(G_OBJECT(newitem), DBUSMENU_MENUITEM_SIGNAL_PROPERTY_CHANGED, G_CALLBACK(calendar_prop_change_cb), ido);
+
+ /* Run the current values through prop changed */
+ GVariant * propval = NULL;
+
+ propval = dbusmenu_menuitem_property_get_variant(newitem, CALENDAR_MENUITEM_PROP_MARKS);
+ if (propval != NULL) {
+ calendar_prop_change_cb(newitem, CALENDAR_MENUITEM_PROP_MARKS, propval, ido);
+ }
+
+ propval = dbusmenu_menuitem_property_get_variant(newitem, CALENDAR_MENUITEM_PROP_SET_DATE);
+ if (propval != NULL) {
+ calendar_prop_change_cb(newitem, CALENDAR_MENUITEM_PROP_SET_DATE, propval, ido);
+ }
+
return TRUE;
}
@@ -1359,15 +1452,10 @@ new_timezone_item(DbusmenuMenuitem * newitem,
{
g_return_val_if_fail(DBUSMENU_IS_MENUITEM(newitem), FALSE);
g_return_val_if_fail(DBUSMENU_IS_GTKCLIENT(client), FALSE);
+ g_return_val_if_fail(IS_INDICATOR_DATETIME(user_data), FALSE);
/* Note: not checking parent, it's reasonable for it to be NULL */
-
- IndicatorObject *io = g_object_get_data (G_OBJECT (client), "indicator");
- if (io == NULL) {
- g_warning ("found no indicator to attach the timezone to");
- return FALSE;
- }
- IndicatorDatetime *self = INDICATOR_DATETIME(io);
+ IndicatorDatetime * self = INDICATOR_DATETIME(user_data);
IndicatorDatetimePrivate *priv = INDICATOR_DATETIME_GET_PRIVATE(self);
// Menu item with a radio button and a right aligned time
@@ -1394,7 +1482,7 @@ new_timezone_item(DbusmenuMenuitem * newitem,
/* Usually either the time or the count on the individual
item. */
mi_data->right = gtk_label_new("");
- gtk_size_group_add_widget(indicator_right_group, mi_data->right);
+ gtk_size_group_add_widget(self->priv->indicator_right_group, mi_data->right);
gtk_misc_set_alignment(GTK_MISC(mi_data->right), 1.0, 0.5);
gtk_box_pack_start(GTK_BOX(hbox), mi_data->right, FALSE, FALSE, 0);
gtk_widget_show(mi_data->right);
@@ -1444,17 +1532,6 @@ get_menu (IndicatorObject * io)
{
IndicatorDatetime * self = INDICATOR_DATETIME(io);
- if (self->priv->menu == NULL) {
- self->priv->menu = dbusmenu_gtkmenu_new(SERVICE_NAME, MENU_OBJ);
- }
-
- DbusmenuGtkClient *client = dbusmenu_gtkmenu_get_client(self->priv->menu);
- g_object_set_data (G_OBJECT (client), "indicator", io);
-
- dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), DBUSMENU_CALENDAR_MENUITEM_TYPE, new_calendar_item);
- dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), APPOINTMENT_MENUITEM_TYPE, new_appointment_item);
- dbusmenu_client_add_type_handler(DBUSMENU_CLIENT(client), TIMEZONE_MENUITEM_TYPE, new_timezone_item);
-
return GTK_MENU(self->priv->menu);
}
diff --git a/src/settings-shared.h b/src/settings-shared.h
index cdbb063..da66205 100644
--- a/src/settings-shared.h
+++ b/src/settings-shared.h
@@ -34,6 +34,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#define SETTINGS_SHOW_EVENTS_S "show-events"
#define SETTINGS_SHOW_LOCATIONS_S "show-locations"
#define SETTINGS_LOCATIONS_S "locations"
+#define SETTINGS_TIMEZONE_NAME_S "timezone-name"
enum {
SETTINGS_TIME_LOCALE = 0,
@@ -50,8 +51,8 @@ enum {
a clock showing 24-hour time without seconds. */
#define DEFAULT_TIME_24_FORMAT N_("%H:%M")
-#define DEFAULT_TIME_FORMAT DEFAULT_TIME_12_FORMAT
-#define DEFAULT_TIME_FORMAT_WITH_DAY DEFAULT_TIME_12_FORMAT
+#define DEFAULT_TIME_FORMAT DEFAULT_TIME_12_FORMAT
+#define DEFAULT_TIME_FORMAT_WITH_DAY DEFAULT_TIME_12_FORMAT_WITH_DAY
/* TRANSLATORS: A format string for the strftime function for
a clock showing the day of the week and the time in 12-hour format without
diff --git a/src/timezone-completion.c b/src/timezone-completion.c
index aaf6bdc..ad04d0c 100644
--- a/src/timezone-completion.c
+++ b/src/timezone-completion.c
@@ -24,6 +24,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
#include <json-glib/json-glib.h>
#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
#include <glib/gi18n.h>
#include "timezone-completion.h"
#include "tz.h"
@@ -41,6 +42,7 @@ struct _TimezoneCompletionPrivate
GtkEntry * entry;
guint queued_request;
guint changed_id;
+ guint keypress_id;
GCancellable * cancel;
gchar * request_text;
GHashTable * request_table;
@@ -79,12 +81,48 @@ save_and_use_model (TimezoneCompletion * completion, GtkTreeModel * model)
gtk_entry_completion_set_match_func (GTK_ENTRY_COMPLETION (completion), match_func, NULL, NULL);
gtk_entry_completion_set_model (GTK_ENTRY_COMPLETION (completion), model);
- gtk_entry_completion_complete (GTK_ENTRY_COMPLETION (completion));
- /* By this time, the changed signal has come and gone. We didn't give a
- model to use, so no popup appeared for user. Poke the entry again to show
- popup in 300ms. */
- g_signal_emit_by_name (priv->entry, "changed");
+ if (priv->entry != NULL) {
+ gtk_entry_completion_complete (GTK_ENTRY_COMPLETION (completion));
+
+ /* By this time, the changed signal has come and gone. We didn't give a
+ model to use, so no popup appeared for user. Poke the entry again to show
+ popup in 300ms. */
+ g_signal_emit_by_name (priv->entry, "changed");
+ }
+}
+
+static gint
+sort_zone (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
+ gpointer user_data)
+{
+ /* Anything that has text as a prefix goes first, in mostly sorted order.
+ Then everything else goes after, in mostly sorted order. */
+ const gchar *casefolded_text = (const gchar *)user_data;
+
+ const gchar *namea = NULL, *nameb = NULL;
+ gtk_tree_model_get (model, a, TIMEZONE_COMPLETION_NAME, &namea, -1);
+ gtk_tree_model_get (model, b, TIMEZONE_COMPLETION_NAME, &nameb, -1);
+
+ gchar *casefolded_namea = NULL, *casefolded_nameb = NULL;
+ casefolded_namea = g_utf8_casefold (namea, -1);
+ casefolded_nameb = g_utf8_casefold (nameb, -1);
+
+ gboolean amatches = FALSE, bmatches = FALSE;
+ amatches = strncmp (casefolded_text, casefolded_namea, strlen(casefolded_text)) == 0;
+ bmatches = strncmp (casefolded_text, casefolded_nameb, strlen(casefolded_text)) == 0;
+
+ gint rv;
+ if (amatches && !bmatches)
+ rv = -1;
+ else if (bmatches && !amatches)
+ rv = 1;
+ else
+ rv = g_utf8_collate (casefolded_namea, casefolded_nameb);
+
+ g_free (casefolded_namea);
+ g_free (casefolded_nameb);
+ return rv;
}
static void
@@ -99,14 +137,15 @@ json_parse_ready (GObject *object, GAsyncResult *res, gpointer user_data)
json_parser_load_from_stream_finish (JSON_PARSER (object), res, &error);
- if (priv->cancel && (error == NULL || error->code != G_IO_ERROR_CANCELLED)) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && priv->cancel) {
g_cancellable_reset (priv->cancel);
}
if (error != NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ save_and_use_model (completion, priv->initial_model);
g_warning ("Could not parse geoname JSON data: %s", error->message);
g_error_free (error);
- save_and_use_model (completion, priv->initial_model);
return;
}
@@ -179,6 +218,13 @@ json_parse_ready (GObject *object, GAsyncResult *res, gpointer user_data)
TIMEZONE_COMPLETION_LONGITUDE, longitude,
TIMEZONE_COMPLETION_LATITUDE, latitude,
-1);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+ TIMEZONE_COMPLETION_NAME, sort_zone,
+ g_utf8_casefold(priv->request_text, -1),
+ g_free);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ TIMEZONE_COMPLETION_NAME,
+ GTK_SORT_ASCENDING);
}
prev_name = name;
@@ -189,6 +235,20 @@ json_parse_ready (GObject *object, GAsyncResult *res, gpointer user_data)
json_reader_end_element (reader);
}
+ if (strlen (priv->request_text) < 4) {
+ gchar * lower_text = g_ascii_strdown (priv->request_text, -1);
+ if (g_strcmp0 (lower_text, "ut") == 0 ||
+ g_strcmp0 (lower_text, "utc") == 0) {
+ GtkTreeIter iter;
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ TIMEZONE_COMPLETION_ZONE, "UTC",
+ TIMEZONE_COMPLETION_NAME, "UTC",
+ -1);
+ }
+ g_free (lower_text);
+ }
+
save_and_use_model (completion, GTK_TREE_MODEL (store));
g_object_unref (G_OBJECT (reader));
}
@@ -203,14 +263,15 @@ geonames_data_ready (GObject *object, GAsyncResult *res, gpointer user_data)
stream = g_file_read_finish (G_FILE (object), res, &error);
- if (priv->cancel && (error == NULL || error->code != G_IO_ERROR_CANCELLED)) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && priv->cancel) {
g_cancellable_reset (priv->cancel);
}
if (error != NULL) {
+ if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+ save_and_use_model (completion, priv->initial_model);
g_warning ("Could not connect to geoname lookup server: %s", error->message);
g_error_free (error);
- save_and_use_model (completion, priv->initial_model);
return;
}
@@ -257,6 +318,7 @@ entry_changed (GtkEntry * entry, TimezoneCompletion * completion)
if (priv->queued_request) {
g_source_remove (priv->queued_request);
+ priv->queued_request = 0;
}
/* See if we've already got this one */
@@ -272,6 +334,94 @@ entry_changed (GtkEntry * entry, TimezoneCompletion * completion)
gtk_entry_completion_complete (GTK_ENTRY_COMPLETION (completion));
}
+static GtkWidget *
+get_descendent (GtkWidget * parent, GType type)
+{
+ if (g_type_is_a (G_OBJECT_TYPE (parent), type))
+ return parent;
+
+ if (GTK_IS_CONTAINER (parent)) {
+ GList * children = gtk_container_get_children (GTK_CONTAINER (parent));
+ GList * iter;
+ for (iter = children; iter; iter = iter->next) {
+ GtkWidget * found = get_descendent (GTK_WIDGET (iter->data), type);
+ if (found) {
+ g_list_free (children);
+ return found;
+ }
+ }
+ g_list_free (children);
+ }
+
+ return NULL;
+}
+
+/**
+ * The popup window and its GtkTreeView are private to our parent completion
+ * object. We can't get access to discover if there is a highlighted item or
+ * even if the window is showing right now. So this is a super hack to find
+ * it by looking through our toplevel's window group and finding a window with
+ * a GtkTreeView that points at our model. There should be only one ever, so
+ * we'll use the first one we find.
+ */
+static GtkTreeView *
+find_popup_treeview (GtkWidget * widget, GtkTreeModel * model)
+{
+ GtkWidget * toplevel = gtk_widget_get_toplevel (widget);
+ if (!GTK_IS_WINDOW (toplevel))
+ return NULL;
+
+ GtkWindowGroup * group = gtk_window_get_group (GTK_WINDOW (toplevel));
+ GList * windows = gtk_window_group_list_windows (group);
+ GList * iter;
+ for (iter = windows; iter; iter = iter->next) {
+ if (iter->data == toplevel)
+ continue; // Skip our own window, we don't have it
+ GtkWidget * view = get_descendent (GTK_WIDGET (iter->data), GTK_TYPE_TREE_VIEW);
+ if (view != NULL) {
+ GtkTreeModel * tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
+ if (GTK_IS_TREE_MODEL_FILTER (tree_model))
+ tree_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (tree_model));
+ if (tree_model == model) {
+ g_list_free (windows);
+ return GTK_TREE_VIEW (view);
+ }
+ }
+ }
+ g_list_free (windows);
+
+ return NULL;
+}
+
+static gboolean
+entry_keypress (GtkEntry * entry, GdkEventKey *event, TimezoneCompletion * completion)
+{
+ if (event->keyval == GDK_ISO_Enter ||
+ event->keyval == GDK_KP_Enter ||
+ event->keyval == GDK_Return) {
+ /* Make sure that user has a selection to choose, otherwise ignore */
+ GtkTreeModel * model = gtk_entry_completion_get_model (GTK_ENTRY_COMPLETION (completion));
+ GtkTreeView * view = find_popup_treeview (GTK_WIDGET (entry), model);
+ if (view == NULL) {
+ // Just beep if popup hasn't appeared yet.
+ gtk_widget_error_bell (GTK_WIDGET (entry));
+ return TRUE;
+ }
+
+ GtkTreeSelection * sel = gtk_tree_view_get_selection (view);
+ GtkTreeModel * sel_model = NULL;
+ if (!gtk_tree_selection_get_selected (sel, &sel_model, NULL)) {
+ // No selection, we should help them out and select first item in list
+ GtkTreeIter iter;
+ if (gtk_tree_model_get_iter_first (sel_model, &iter))
+ gtk_tree_selection_select_iter (sel, &iter);
+ // And fall through to normal handler code
+ }
+ }
+
+ return FALSE;
+}
+
void
timezone_completion_watch_entry (TimezoneCompletion * completion, GtkEntry * entry)
{
@@ -282,15 +432,22 @@ timezone_completion_watch_entry (TimezoneCompletion * completion, GtkEntry * ent
priv->queued_request = 0;
}
if (priv->entry) {
- g_source_remove (priv->changed_id);
+ g_signal_handler_disconnect (priv->entry, priv->changed_id);
+ g_signal_handler_disconnect (priv->entry, priv->keypress_id);
g_object_remove_weak_pointer (G_OBJECT (priv->entry), (gpointer *)&priv->entry);
+ gtk_entry_set_completion (priv->entry, NULL);
}
guint id = g_signal_connect (entry, "changed", G_CALLBACK (entry_changed), completion);
priv->changed_id = id;
+ id = g_signal_connect (entry, "key-press-event", G_CALLBACK (entry_keypress), completion);
+ priv->keypress_id = id;
+
priv->entry = entry;
g_object_add_weak_pointer (G_OBJECT (entry), (gpointer *)&priv->entry);
+
+ gtk_entry_set_completion (entry, GTK_ENTRY_COMPLETION (completion));
}
static GtkListStore *
@@ -332,6 +489,13 @@ get_initial_model (void)
g_free (name);
}
+ GtkTreeIter iter;
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ TIMEZONE_COMPLETION_ZONE, "UTC",
+ TIMEZONE_COMPLETION_NAME, "UTC",
+ -1);
+
tz_db_free (db);
return store;
}
@@ -340,29 +504,24 @@ static void
data_func (GtkCellLayout *cell_layout, GtkCellRenderer *cell,
GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer user_data)
{
- GValue name_val = {0}, admin1_val = {0}, country_val = {0};
const gchar * name, * admin1, * country;
- gtk_tree_model_get_value (GTK_TREE_MODEL (tree_model), iter, TIMEZONE_COMPLETION_NAME, &name_val);
- gtk_tree_model_get_value (GTK_TREE_MODEL (tree_model), iter, TIMEZONE_COMPLETION_ADMIN1, &admin1_val);
- gtk_tree_model_get_value (GTK_TREE_MODEL (tree_model), iter, TIMEZONE_COMPLETION_COUNTRY, &country_val);
-
- name = g_value_get_string (&name_val);
- admin1 = g_value_get_string (&admin1_val);
- country = g_value_get_string (&country_val);
+ gtk_tree_model_get (GTK_TREE_MODEL (tree_model), iter,
+ TIMEZONE_COMPLETION_NAME, &name,
+ TIMEZONE_COMPLETION_ADMIN1, &admin1,
+ TIMEZONE_COMPLETION_COUNTRY, &country,
+ -1);
gchar * user_name;
- if (admin1 == NULL || admin1[0] == 0) {
+ if (country == NULL || country[0] == 0) {
+ user_name = g_strdup (name);
+ } else if (admin1 == NULL || admin1[0] == 0) {
user_name = g_strdup_printf ("%s <small>(%s)</small>", name, country);
} else {
user_name = g_strdup_printf ("%s <small>(%s, %s)</small>", name, admin1, country);
}
g_object_set (G_OBJECT (cell), "markup", user_name, NULL);
-
- g_value_unset (&name_val);
- g_value_unset (&admin1_val);
- g_value_unset (&country_val);
}
static void
@@ -410,10 +569,17 @@ timezone_completion_dispose (GObject * object)
TimezoneCompletionPrivate * priv = TIMEZONE_COMPLETION_GET_PRIVATE (completion);
if (priv->changed_id) {
- g_source_remove (priv->changed_id);
+ if (priv->entry)
+ g_signal_handler_disconnect (priv->entry, priv->changed_id);
priv->changed_id = 0;
}
+ if (priv->keypress_id) {
+ if (priv->entry)
+ g_signal_handler_disconnect (priv->entry, priv->keypress_id);
+ priv->keypress_id = 0;
+ }
+
if (priv->entry != NULL) {
g_object_remove_weak_pointer (G_OBJECT (priv->entry), (gpointer *)&priv->entry);
}
diff --git a/src/utils.c b/src/utils.c
index 537495b..d8851aa 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -233,6 +233,8 @@ generate_format_string_at_time (GDateTime * time)
g_date_time_unref(future_bound);
}
+ g_date_time_unref (now);
+
return generate_format_string_full(show_day, show_date);
}