2010-10-13 21:36:52 +00:00
|
|
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
|
|
|
|
const GLib = imports.gi.GLib;
|
|
|
|
const Gio = imports.gi.Gio;
|
|
|
|
const Lang = imports.lang;
|
|
|
|
const Mainloop = imports.mainloop;
|
|
|
|
const Cairo = imports.cairo;
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
|
|
const Shell = imports.gi.Shell;
|
|
|
|
const St = imports.gi.St;
|
|
|
|
const Gettext = imports.gettext.domain('gnome-shell');
|
|
|
|
const _ = Gettext.gettext;
|
|
|
|
|
|
|
|
const Main = imports.ui.main;
|
|
|
|
const PanelMenu = imports.ui.panelMenu;
|
|
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
|
|
const Calendar = imports.ui.calendar;
|
|
|
|
|
|
|
|
const CLOCK_FORMAT_KEY = 'format';
|
|
|
|
const CLOCK_CUSTOM_FORMAT_KEY = 'custom-format';
|
|
|
|
const CLOCK_SHOW_DATE_KEY = 'show-date';
|
|
|
|
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
|
|
|
|
|
|
|
|
function DateMenuButton() {
|
|
|
|
this._init();
|
|
|
|
}
|
|
|
|
|
|
|
|
function on_vert_sep_repaint (area)
|
|
|
|
{
|
|
|
|
let cr = area.get_context();
|
|
|
|
let themeNode = area.get_theme_node();
|
|
|
|
let [width, height] = area.get_surface_size();
|
|
|
|
let found, margin, gradientHeight;
|
2010-10-28 17:33:12 +00:00
|
|
|
[found, margin] = themeNode.lookup_length('-margin-vertical', false);
|
|
|
|
[found, gradientWidth] = themeNode.lookup_length('-gradient-width', false);
|
2010-10-13 21:36:52 +00:00
|
|
|
let startColor = new Clutter.Color();
|
2010-10-28 17:33:12 +00:00
|
|
|
themeNode.lookup_color('-gradient-start', false, startColor);
|
2010-10-13 21:36:52 +00:00
|
|
|
let endColor = new Clutter.Color();
|
2010-10-28 17:33:12 +00:00
|
|
|
themeNode.lookup_color('-gradient-end', false, endColor);
|
2010-10-13 21:36:52 +00:00
|
|
|
|
|
|
|
let gradientHeight = (height - margin * 2);
|
|
|
|
let gradientOffset = (width - gradientWidth) / 2;
|
|
|
|
let pattern = new Cairo.LinearGradient(gradientOffset, margin, gradientOffset + gradientWidth, height - margin);
|
|
|
|
pattern.addColorStopRGBA(0, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
|
|
|
|
pattern.addColorStopRGBA(0.5, endColor.red / 255, endColor.green / 255, endColor.blue / 255, endColor.alpha / 255);
|
|
|
|
pattern.addColorStopRGBA(1, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
|
|
|
|
cr.setSource(pattern);
|
|
|
|
cr.rectangle(gradientOffset, margin, gradientWidth, gradientHeight);
|
|
|
|
cr.fill();
|
|
|
|
};
|
|
|
|
|
|
|
|
DateMenuButton.prototype = {
|
|
|
|
__proto__: PanelMenu.Button.prototype,
|
|
|
|
|
|
|
|
_init: function() {
|
|
|
|
let item;
|
2010-10-28 17:33:12 +00:00
|
|
|
let hbox;
|
|
|
|
let vbox;
|
2010-10-13 21:36:52 +00:00
|
|
|
|
|
|
|
PanelMenu.Button.prototype._init.call(this, St.Align.START);
|
|
|
|
|
|
|
|
this._clock = new St.Label();
|
|
|
|
this.actor.set_child(this._clock);
|
|
|
|
|
2010-10-28 17:33:12 +00:00
|
|
|
hbox = new St.BoxLayout({name: 'calendarHBox'});
|
|
|
|
this.menu.addActor(hbox);
|
|
|
|
|
|
|
|
// Fill up the first column
|
|
|
|
//
|
2010-12-15 22:32:35 +00:00
|
|
|
vbox = new St.BoxLayout({vertical: true, name: 'calendarVBox1'});
|
2010-10-28 17:33:12 +00:00
|
|
|
hbox.add(vbox);
|
|
|
|
|
|
|
|
// Date
|
2010-10-13 21:36:52 +00:00
|
|
|
this._date = new St.Label();
|
|
|
|
this._date.style_class = 'datemenu-date-label';
|
2010-10-28 17:33:12 +00:00
|
|
|
vbox.add(this._date);
|
2010-10-13 21:36:52 +00:00
|
|
|
|
2010-11-30 19:31:32 +00:00
|
|
|
this._taskList = new Calendar.EventsList();
|
|
|
|
|
2010-10-28 17:33:12 +00:00
|
|
|
// Calendar
|
2010-11-30 19:31:32 +00:00
|
|
|
this._calendar = new Calendar.Calendar(this._taskList);
|
2010-10-28 17:33:12 +00:00
|
|
|
vbox.add(this._calendar.actor);
|
|
|
|
|
|
|
|
// Add vertical separator
|
|
|
|
//
|
|
|
|
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
|
|
|
pseudo_class: 'highlighted' });
|
|
|
|
item.set_width(25); // TODO: don't hard-code the width
|
|
|
|
item.connect('repaint', Lang.bind(this, on_vert_sep_repaint));
|
|
|
|
hbox.add(item);
|
|
|
|
|
|
|
|
// Fill up the second column
|
|
|
|
//
|
|
|
|
// Event list
|
2010-12-15 22:32:35 +00:00
|
|
|
hbox.add(this._taskList.actor);
|
2010-10-28 17:33:12 +00:00
|
|
|
// Update event list when opening the menu ..
|
2010-11-30 15:50:20 +00:00
|
|
|
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, is_open) {
|
|
|
|
if (is_open) {
|
|
|
|
this._calendar.clearButtonsState();
|
|
|
|
this._taskList.update();
|
|
|
|
}
|
2010-10-20 18:30:35 +00:00
|
|
|
}));
|
2010-10-28 17:33:12 +00:00
|
|
|
// .. and also update when selecting a new day
|
2010-10-20 18:30:35 +00:00
|
|
|
this._calendar.connect('activate', Lang.bind(this, function(obj, day) {
|
2010-11-30 15:50:20 +00:00
|
|
|
let now = new Date();
|
|
|
|
if (now.getDate() == day.getDate() &&
|
|
|
|
now.getMonth() == day.getMonth() &&
|
|
|
|
now.getFullYear() == day.getFullYear()) {
|
|
|
|
// Today - show: Today, Tomorrow and This Week
|
|
|
|
this._taskList.update();
|
|
|
|
} else {
|
|
|
|
// Not Today - show only events from that day
|
|
|
|
this._taskList.showDay(day);
|
|
|
|
}
|
2010-10-20 18:30:35 +00:00
|
|
|
}));
|
2010-10-28 17:33:12 +00:00
|
|
|
// .. TODO: and also update when changing the month
|
2010-10-20 18:30:35 +00:00
|
|
|
|
2010-10-28 17:33:12 +00:00
|
|
|
// Done with hbox for calendar and event list
|
|
|
|
//
|
|
|
|
|
|
|
|
// Add separator
|
2010-10-13 21:36:52 +00:00
|
|
|
item = new PopupMenu.PopupSeparatorMenuItem();
|
|
|
|
this.menu.addMenuItem(item);
|
|
|
|
|
2010-10-28 17:33:12 +00:00
|
|
|
// Add button to get to the Date and Time settings
|
2010-10-13 21:36:52 +00:00
|
|
|
item = new PopupMenu.PopupImageMenuItem(_("Date and Time Settings"), 'gnome-shell-clock-preferences');
|
|
|
|
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
|
|
|
this.menu.addMenuItem(item);
|
|
|
|
|
2010-10-28 17:33:12 +00:00
|
|
|
// Track changes to clock settings
|
2010-10-13 21:36:52 +00:00
|
|
|
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
|
|
|
|
this._clockSettings.connect('changed', Lang.bind(this, this._clockSettingsChanged));
|
|
|
|
|
|
|
|
// Start the clock
|
|
|
|
this._updateClockAndDate();
|
|
|
|
},
|
|
|
|
|
|
|
|
_clockSettingsChanged: function() {
|
|
|
|
this._updateClockAndDate();
|
|
|
|
},
|
|
|
|
|
|
|
|
_updateClockAndDate: function() {
|
|
|
|
let format = this._clockSettings.get_string(CLOCK_FORMAT_KEY);
|
|
|
|
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
|
|
|
|
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
|
|
|
|
|
|
|
|
let clockFormat;
|
|
|
|
let dateFormat;
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case 'unix':
|
|
|
|
// force updates every second
|
|
|
|
showSeconds = true;
|
|
|
|
clockFormat = '%s';
|
|
|
|
break;
|
|
|
|
case 'custom':
|
|
|
|
// force updates every second
|
|
|
|
showSeconds = true;
|
|
|
|
clockFormat = this._clockSettings.get_string(CLOCK_CUSTOM_FORMAT_KEY);
|
|
|
|
break;
|
|
|
|
case '24-hour':
|
|
|
|
if (showDate)
|
|
|
|
/* Translators: This is the time format with date used
|
|
|
|
in 24-hour mode. */
|
|
|
|
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
|
|
|
|
: _("%a %b %e, %R");
|
|
|
|
else
|
|
|
|
/* Translators: This is the time format without date used
|
|
|
|
in 24-hour mode. */
|
|
|
|
clockFormat = showSeconds ? _("%a %R:%S")
|
|
|
|
: _("%a %R");
|
|
|
|
break;
|
|
|
|
case '12-hour':
|
|
|
|
default:
|
|
|
|
if (showDate)
|
|
|
|
/* Translators: This is a time format with date used
|
|
|
|
for AM/PM. */
|
|
|
|
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
|
|
|
|
: _("%a %b %e, %l:%M %p");
|
|
|
|
else
|
|
|
|
/* Translators: This is a time format without date used
|
|
|
|
for AM/PM. */
|
|
|
|
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
|
|
|
|
: _("%a %l:%M %p");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
let displayDate = new Date();
|
|
|
|
let msecRemaining;
|
|
|
|
if (showSeconds) {
|
|
|
|
msecRemaining = 1000 - displayDate.getMilliseconds();
|
|
|
|
if (msecRemaining < 50) {
|
|
|
|
displayDate.setSeconds(displayDate.getSeconds() + 1);
|
|
|
|
msecRemaining += 1000;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
|
|
|
|
displayDate.getMilliseconds());
|
|
|
|
if (msecRemaining < 500) {
|
|
|
|
displayDate.setMinutes(displayDate.getMinutes() + 1);
|
|
|
|
msecRemaining += 60000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
|
|
|
|
|
|
|
|
/* Translators: This is the date format to use */
|
|
|
|
dateFormat = _("%B %e, %Y");
|
|
|
|
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
|
|
|
|
|
|
|
|
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClockAndDate));
|
|
|
|
return false;
|
|
|
|
},
|
|
|
|
|
|
|
|
_onPreferencesActivate: function() {
|
|
|
|
Main.overview.hide();
|
|
|
|
this._spawn(['gnome-shell-clock-preferences']);
|
|
|
|
},
|
|
|
|
|
|
|
|
_spawn: function(args) {
|
|
|
|
// FIXME: once Shell.Process gets support for signalling
|
|
|
|
// errors we should pop up an error dialog or something here
|
|
|
|
// on failure
|
|
|
|
let p = new Shell.Process({'args' : args});
|
|
|
|
p.run();
|
|
|
|
}
|
|
|
|
};
|