pax_global_header00006660000000000000000000000064121341212230014501gustar00rootroot0000000000000052 comment=8a336e4e25bdb62fc0f5deb7893e240b71114e84 gsimplecal-0.8/000075500000000000000000000000001213412122300134665ustar00rootroot00000000000000gsimplecal-0.8/.empty000064400000000000000000000000001213412122300146130ustar00rootroot00000000000000gsimplecal-0.8/.gear/000075500000000000000000000000001213412122300144625ustar00rootroot00000000000000gsimplecal-0.8/.gear/rules000064400000000000000000000000631213412122300155360ustar00rootroot00000000000000tar: . name=@name@-@version@ base=@name@-@version@ gsimplecal-0.8/.gitignore000064400000000000000000000003101213412122300154500ustar00rootroot00000000000000*.o aclocal.m4 autom4te.cache/ config.log config.status configure depcomp install-sh missing src/.deps/ Makefile Makefile.in doc/Makefile doc/Makefile.in src/Makefile src/Makefile.in src/gsimplecal gsimplecal-0.8/AUTHORS000064400000000000000000000005321213412122300145360ustar00rootroot00000000000000Authors & Contributors: * Dmitry Medvinsky * Kim Hempel : issue reports, patches * Victor Feight : Arch Linux package * Joshua Saddler : Gentoo Linux package * Filip Pytloun : Fedora Linux package * maelnor: Gentoo Linux package gsimplecal-0.8/ChangeLog000064400000000000000000000011321213412122300152350ustar00rootroot000000000000002011-04-03: v0.8: - Fix segmentation fault in the clock + Add keyboard bindings to go to the current date 2011-03-26: v0.7: + Mark today even when selecting some other day 2010-10-18: v0.6: + Add next_month and prev_month command line arguments + Add more config options (see man page) 2010-07-13: v0.5: + Add keyboard shortcuts to close the gsimplecal * Add program crashes handling + Add keyboard shortcuts to switch months and years 2010-05-29: v0.4: + Use semaphores instead of libunique 2010-03-27: v0.3: + Migrate to autotools 2010-03-22: v0.2: + World clocks 2009-07-04: v0.1: + Calendar gsimplecal-0.8/LICENSE000064400000000000000000000027241213412122300145000ustar00rootroot00000000000000Copyright (c) 2009, Dmitry Medvinsky Some rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. gsimplecal-0.8/Makefile.am000064400000000000000000000000221213412122300155140ustar00rootroot00000000000000SUBDIRS = src doc gsimplecal-0.8/NEWS000064400000000000000000000000001213412122300141530ustar00rootroot00000000000000gsimplecal-0.8/README000064400000000000000000000000551213412122300143460ustar00rootroot00000000000000gsimplecal - lightweight gui calendar applet gsimplecal-0.8/README.rst000064400000000000000000000020721213412122300151560ustar00rootroot00000000000000============ Gsimplecal ============ Gsimplecal is a lightweight calendar applet written in C++ using GTK2. It was intentionally made for use with tint2_ panel in the openbox_ environment to be launched upon clock click, but of course it will work without it. In fact, binding the gsimplecal to some hotkey in you window manager will probably make you happy. The thing is that when it is started it first shows up, when you run it again it closes the running instance. In that way it is very easy to integrate anywhere. No need to write some wrapper scripts or whatever. Also, you can configure it to not only show the calendar, but also display multiple clocks for different world timezones. Read the manual page for the details (there is info about keyboard controls as well!). Feel free to ask me anything and do not hesitate to post an issue. I don't get a lot of questions and I feel kind of lonely. ;) .. _tint2: http://code.google.com/p/tint2/ .. _openbox: http://openbox.org/wiki/Main_Page .. image:: https://github.com/dmedvinsky/gsimplecal/raw/gh-pages/g/scrot2.png gsimplecal-0.8/autogen.sh000075500000000000000000000000421213412122300154630ustar00rootroot00000000000000#!/bin/sh autoreconf -i -s -f -v gsimplecal-0.8/autoreconf.sh000075500000000000000000000000471213412122300161730ustar00rootroot00000000000000#!/bin/sh autoreconf --force --install gsimplecal-0.8/configure.ac000064400000000000000000000027551213412122300157650ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) AC_INIT([gsimplecal], [0.8], [http://github.com/dmedvinsky/gsimplecal/issues], [gsimplecal], [http://github.com/dmedvinsky/gsimplecal]) AM_INIT_AUTOMAKE([-Wall -Werror foreign]) AC_CONFIG_SRCDIR([src/gsimplecal.cpp]) # Checks for programs. AC_LANG([C++]) AC_PROG_CXX AC_PROG_INSTALL PKG_PROG_PKG_CONFIG # Checks for libraries. PKG_CHECK_MODULES([GTK2], [gtk+-2.0]) AC_SUBST(GTK2_CFLAGS) AC_SUBST(GTK2_LIBS) # Checks for header files. AC_CHECK_HEADERS([iostream \ string \ sstream \ fstream \ vector \ cstdlib \ stdlib.h \ sys/time.h \ sys/types.h \ sys/ipc.h \ sys/sem.h \ signal.h \ limits.h]) # Checks for typedefs, structures, and compiler characteristics. # Checks for library functions. AC_CHECK_FUNCS([atexit \ gettimeofday \ setenv \ signal \ kill \ semget \ semctl \ ftok \ readlink]) # AM_CPPFLAGS="-Wall" AM_LDFLAGS="-Wl,--as-needed" AC_SUBST(AM_CFLAGS) AC_SUBST(AM_LDFLAGS) AC_CONFIG_FILES([Makefile doc/Makefile src/Makefile]) AC_OUTPUT gsimplecal-0.8/doc/000075500000000000000000000000001213412122300142335ustar00rootroot00000000000000gsimplecal-0.8/doc/Makefile.am000064400000000000000000000000721213412122300162660ustar00rootroot00000000000000man1_MANS = $(PACKAGE_NAME).1 EXTRA_DIST = $(man1_MANS) gsimplecal-0.8/doc/gsimplecal.1000064400000000000000000000101411213412122300164320ustar00rootroot00000000000000.TH GSIMPLECAL 1 "2010-10-10" .SH NAME gsimplecal \- lightweight calendar applet .SH SYNOPSIS .B gsimplecal .br .B gsimplecal next_month .br .B gsimplecal prev_month .SH DESCRIPTION This manual page documents the usage of the .B gsimplecal command. .PP .B gsimplecal is a lightweight calendar applet. When it is started, it first shows up, when you run it again, it closes the running instance. It was intentionally made for use with tint2 panel to be launched upon clock click, but of course it will work without it, you can bind it to some hotkey in you window manager, for example. .PP When you provide one of the arguments — .B next_month or .B prev_month — instead of closing the running instance, the displaying month is changed. .SH CONFIGURATION .PP You may configure gsimplecal to display different world timezones clocks. To make it, you should create .nh \fB$XDG_CONFIG_HOME/gsimplecal/config\fP .ny file (usually it will be .nh ~/.config/gsimplecal/config) .ny with the following contents: .IP show_calendar = 1 .br show_timezones = 1 .br mark_today = 1 .br clock_format = %a %d %b %H:%M .br mainwindow_decorated = 0 .br mainwindow_keep_above = 1 .br mainwindow_sticky = 0 .br mainwindow_skip_taskbar = 1 .br mainwindow_position = none .br clock_label = UTC .br clock_tz = :UTC .br clock_label = Local .br clock_tz = .PP The options are pretty self explanatory, but here is detailed description: .TP 5 \fBshow_calendar\fP: 1 or 0, defaults to 1. Sets whether the calendar should be shown. Most users want this option to be 1. .TP 5 \fBshow_timezones\fP: 1 or 0, defaults to 0. Sets whether the different timezone clocks should be shown. .TP 5 \fBmark_today\fP: 1 or 0, defaults to 1. Sets whether today's date will be marked in the calendar (besides the default selection, i.e. when you click on the other day, today will remain marked somehow, e.g. in bold print). .TP 5 \fBclock_format\fP: string Sets the clocks format. Look \fIman strftime\fP for the possible formats. .TP 5 \fBmainwindow_decorated\fP: 1 or 0, defaults to 0. Tells your window manager to decorate or not to decorate the main window. .TP 5 \fBmainwindow_keep_above\fP: 1 or 0, defaults to 1. Sets whether the main window should be placed on top of other windows by your window manager. .TP 5 \fBmainwindow_sticky\fP: 1 or 0, defaults to 0. Tells your window manager to show gsimplecal on all desktops. .TP 5 \fBmainwindow_skip_taskbar\fP: 1 or 0, defaults to 1. Sets whether the main window should be shown in the task list by your panel or window manager. .TP 5 \fBmainwindow_position\fP: mouse|center|none, defaults to mouse. Tells your window manager where to place the gsimplecal window: .TP 10 \fBmouse\fP .br close to the mouse cursor position (this one is useful when you bind gsimplecal on some mouse click command); .TP 10 \fBcenter\fP .br in the center of the screen; .TP 10 \fBnone\fP .br it's up to your window manager to decide, where to place the window (this one is useful when you bind gsimplecal invocation on some hotkey, so you can configure your window manager to place gsimplecal in some predefined position). .TP 5 \fBclock_label\fP and \fBclock_tz\fP: string These two options should go in pairs and \fBmust\fP be in the order given. .br Each pair creates new clock. The clock_label variable sets the string to be displayed near the clock, the clock_tz sets the timezone. .br If you omit the value for clock_tz, local time will be shown. .br For a list of timezones see \fIman timezone\fP, or \fIls /usr/share/zoneinfo\fP .SH KEYBOARD ACCELERATORS .PP You may use the following keyboard accelerators while gsimplecal window has a focus: .IP Escape, Ctrl+w, Ctrl+q: close the window .br j: switch to the next month .br k: switch to the previous month .br J: jump one year forward .br K: jump one year backward .br g, Home: jump to the current date .PP These are not yet configurable, but I'm working on it. .SH REPORTING BUGS .PP Please, report any issues to the gsimplecal issue tracker, available at: .nh http://github.com/dmedvinsky/gsimplecal/issues .ny .SH AUTHOR Created by Dmitry Medvinsky et al. .SH SEE ALSO tzset(3), strftime(3) gsimplecal-0.8/gsimplecal.spec000064400000000000000000000015141213412122300164630ustar00rootroot00000000000000Name: gsimplecal Version: 0.8 Release: alt1.qa1 Summary: Simple and lightweight GTK calendar License: BSD-Style Group: Office Url: https://github.com/dmedvinsky/gsimplecal/ Packager: Egor Glukhov Source: %name-%version.tar BuildRequires: gcc-c++ libgtk+2-devel %description %name is a lightweight calendar application written in C++ using GTK2. It was intentionally made for use with tint2 panel in the openbox environment to be launched upon clock click, but of course it will work without it. %prep %setup %build %autoreconf %configure %make_build %install %makeinstall_std %files %_bindir/%name %_man1dir/* %changelog * Fri Apr 19 2013 Dmitry V. Levin (QA) 0.8-alt1.qa1 - NMU: rebuilt for updated dependencies. * Mon May 9 2011 Egor Glukhov 0.8-alt1 - Initial build gsimplecal-0.8/src/000075500000000000000000000000001213412122300142555ustar00rootroot00000000000000gsimplecal-0.8/src/Boxable.cpp000064400000000000000000000002651213412122300163400ustar00rootroot00000000000000#include #include "Boxable.hpp" void Boxable::addToBox(GtkWidget* box) { if (widget) { gtk_box_pack_start(GTK_BOX(box), widget, false, false, 0); } } gsimplecal-0.8/src/Boxable.hpp000064400000000000000000000003051213412122300163400ustar00rootroot00000000000000#ifndef BOXABLE_HPP #define BOXABLE_HPP #include class Boxable { public: virtual void addToBox(GtkWidget* box); protected: Boxable() {}; GtkWidget* widget; }; #endif gsimplecal-0.8/src/Calendar.cpp000064400000000000000000000041651213412122300165000ustar00rootroot00000000000000#include #include "Calendar.hpp" #include "Config.hpp" void monthChangedCb(GtkCalendar *calendar, gpointer cls) { if (cls) { ((Calendar*)cls)->markToday(); } } Calendar::Calendar() { widget = gtk_calendar_new(); gtk_calendar_set_display_options(GTK_CALENDAR(widget), (GtkCalendarDisplayOptions)(GTK_CALENDAR_SHOW_HEADING + GTK_CALENDAR_SHOW_DAY_NAMES)); Config* config = Config::getInstance(); if (config->mark_today) { // Store today date to know be able to mark it after month changes. gtk_calendar_get_date((GtkCalendar*)widget, &today_year, &today_month, &today_day); markToday(); gtk_signal_connect(GTK_OBJECT(widget), "month-changed", GTK_SIGNAL_FUNC(monthChangedCb), (gpointer)this); } gtk_widget_show(widget); } Calendar::~Calendar() { gtk_widget_destroy(widget); } void Calendar::nextYear() { _change(1, 0); } void Calendar::prevYear() { _change(-1, 0); } void Calendar::nextMonth() { _change(0, 1); } void Calendar::prevMonth() { _change(0, -1); } void Calendar::_change(int year_offset, int month_offset) { int year, month; gtk_calendar_get_date((GtkCalendar*)widget, (guint*)&year, (guint*)&month, NULL); month += month_offset; if (month > 11) { month = 0; year_offset++; } else if (month < 0) { month = 11; year_offset--; } year += year_offset; gtk_calendar_select_month((GtkCalendar*)widget, (guint)month, (guint)year); } bool Calendar::markToday() { guint year, month; gtk_calendar_get_date((GtkCalendar*)widget, &year, &month, NULL); if (year == today_year && month == today_month) { gtk_calendar_mark_day((GtkCalendar*)widget, today_day); return true; } else { gtk_calendar_unmark_day((GtkCalendar*)widget, today_day); return false; } } void Calendar::goToday() { gtk_calendar_select_month((GtkCalendar*)widget, today_month, today_year); gtk_calendar_select_day((GtkCalendar*)widget, today_day); } gsimplecal-0.8/src/Calendar.hpp000064400000000000000000000006771213412122300165110ustar00rootroot00000000000000#ifndef CALENDAR_HPP #define CALENDAR_HPP #include #include "Boxable.hpp" class Calendar : public Boxable { public: Calendar(); ~Calendar(); void nextYear(); void prevYear(); void nextMonth(); void prevMonth(); void goToday(); bool markToday(); protected: void _change(int year_offset, int month_offset); private: guint today_year; guint today_month; guint today_day; }; #endif gsimplecal-0.8/src/Clock.cpp000064400000000000000000000027641213412122300160250ustar00rootroot00000000000000#include #include #include #include #include "Clock.hpp" #include "Config.hpp" using namespace std; Clock::Clock(const string& label, const string& timezone) { this->timezone = timezone; widget = gtk_hbox_new(false, 0); label_label = gtk_label_new(label.c_str()); time_label = gtk_label_new(timezone.c_str()); gtk_box_pack_start(GTK_BOX(widget), label_label, false, false, 10); gtk_box_pack_end(GTK_BOX(widget), time_label, false, false, 10); gtk_widget_show(label_label); gtk_widget_show(time_label); gtk_widget_show(widget); } Clock::~Clock() { gtk_widget_destroy(time_label); gtk_widget_destroy(label_label); gtk_widget_destroy(widget); } void Clock::updateTime(const timeval& time) { string time_text = getTimeForTZ(time, timezone); gtk_label_set_text(GTK_LABEL(time_label), time_text.c_str()); } string Clock::getTimeForTZ(const timeval& time, const string& zone) { struct tm* result; if (zone.length()) { const char* old_tz = getenv("TZ"); setenv("TZ", zone.c_str(), 1); result = localtime(&time.tv_sec); if (old_tz) { setenv("TZ", old_tz, 1); } else { unsetenv("TZ"); } } else { result = localtime(&time.tv_sec); } // format time Config* config = Config::getInstance(); char buffer[64]; strftime(buffer, sizeof(buffer), config->clock_format.c_str(), result); return string(buffer); } gsimplecal-0.8/src/Clock.hpp000064400000000000000000000007221213412122300160220ustar00rootroot00000000000000#ifndef CLOCK_HPP #define CLOCK_HPP #include #include #include #include "Boxable.hpp" using namespace std; class Clock : public Boxable { public: Clock(const string& label, const string& timezone); ~Clock(); void updateTime(const timeval& time); protected: string timezone; GtkWidget* label_label; GtkWidget* time_label; string getTimeForTZ(const timeval& time, const string& zone); }; #endif gsimplecal-0.8/src/Config.cpp000064400000000000000000000076271213412122300162020ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "Config.hpp" using namespace std; Config* Config::_instance = NULL; Config* Config::getInstance() { if (_instance == NULL) { _instance = new Config(); atexit(Destroy); } return _instance; } void Config::Destroy() { delete _instance; _instance = NULL; } Config::Config() { getDefaults(); if (getFile()) { readFile(); } } Config::~Config() { for (unsigned int i = 0; i < clocks.size(); i++) { delete clocks[i]; } } void Config::getDefaults() { show_calendar = true; show_timezones = false; clock_format = string("%H:%M"); mainwindow_decorated = false; mainwindow_keep_above = true; mainwindow_sticky = false; mainwindow_skip_taskbar = true; mainwindow_position = GTK_WIN_POS_MOUSE; mark_today = true; } bool Config::getFile() { // use XDG config dir (~/.config/ usually) char *path_to_config; path_to_config = g_build_filename(g_get_user_config_dir(), "gsimplecal", "config", NULL); if (g_file_test(path_to_config, G_FILE_TEST_EXISTS)) { file.open(path_to_config, ios::in); } g_free(path_to_config); return file.is_open(); } void Config::readFile() { string line; while (!file.eof()) { getline(file, line); parseLine(line); } file.close(); } void Config::parseLine(string line) { if (!line.length() || line[0] == '#') { return; } int pos; for (pos = line.length() - 1; pos >= 0; pos--) { if (line[pos] == '=') { break; } } if (pos == -1) { return; } string var = strip(line.substr(0, pos)); string val = strip(line.substr(pos + 1)); addOption(var, val); } void Config::addOption(string var, string val) { if (var == "show_calendar") { if (!fromString(show_calendar, val)) { show_calendar = true; } } else if (var == "show_timezones") { if (!fromString(show_timezones, val)) { show_timezones = false; } } else if (var == "clock_format") { clock_format = val; } else if (var == "clock_label") { ClockInfo* clockinfo = new ClockInfo; clockinfo->label = val; clocks.push_back(clockinfo); } else if (var == "clock_tz") { clocks[clocks.size() - 1]->timezone = val; } else if (var == "mainwindow_decorated") { if (!fromString(mainwindow_decorated, val)) { mainwindow_decorated = false; } } else if (var == "mainwindow_keep_above") { if (!fromString(mainwindow_keep_above, val)) { mainwindow_keep_above = true; } } else if (var == "mainwindow_sticky") { if (!fromString(mainwindow_sticky, val)) { mainwindow_sticky = false; } } else if (var == "mainwindow_skip_taskbar") { if (!fromString(mainwindow_skip_taskbar, val)) { mainwindow_skip_taskbar = true; } } else if (var == "mainwindow_position") { if (val == "center") { mainwindow_position = GTK_WIN_POS_CENTER; } else if (val == "mouse") { mainwindow_position = GTK_WIN_POS_MOUSE; } else { mainwindow_position = GTK_WIN_POS_NONE; } } else if (var == "mark_today") { if (!fromString(mark_today, val)) { mark_today = true; } } } template bool Config::fromString(T& t, const string& s) { istringstream iss(s); return !(iss >> t).fail(); } string Config::strip(const string& s) { string::size_type const first = s.find_first_not_of(' '); if (first == string::npos) { return string(); } return s.substr(first, s.find_last_not_of(' ') - first + 1); } gsimplecal-0.8/src/Config.hpp000064400000000000000000000017561213412122300162040ustar00rootroot00000000000000#ifndef CONFIG_HPP #define CONFIG_HPP #include #include #include #include #include using namespace std; typedef struct _ClockInfo { string label; string timezone; } ClockInfo; class Config { public: static Config* getInstance(); // options bool show_calendar; bool show_timezones; string clock_format; vector clocks; bool mark_today; bool mainwindow_decorated; bool mainwindow_keep_above; bool mainwindow_sticky; bool mainwindow_skip_taskbar; GtkWindowPosition mainwindow_position; private: static Config* _instance; static void Destroy(); template bool fromString(T& t, const string& s); string strip(string const& str); std::ifstream file; protected: explicit Config(); ~Config(); void getDefaults(); bool getFile(); void readFile(); void parseLine(string line); void addOption(string var, string val); }; #endif gsimplecal-0.8/src/MainWindow.cpp000064400000000000000000000107641213412122300170450ustar00rootroot00000000000000#include #include #include "MainWindow.hpp" #include "Config.hpp" #include "Calendar.hpp" #include "Timezones.hpp" bool closeCallback(GtkAccelGroup *group, GObject *obj, guint keyval, GdkModifierType mod, gpointer user_data) { if (user_data) { ((MainWindow*)user_data)->close(); } return true; } bool nextYearCallback(GtkAccelGroup *group, GObject *obj, guint keyval, GdkModifierType mod, gpointer user_data) { if (user_data) { ((MainWindow*)user_data)->nextYear(); } return true; } bool prevYearCallback(GtkAccelGroup *group, GObject *obj, guint keyval, GdkModifierType mod, gpointer user_data) { if (user_data) { ((MainWindow*)user_data)->prevYear(); } return true; } bool nextMonthCallback(GtkAccelGroup *group, GObject *obj, guint keyval, GdkModifierType mod, gpointer user_data) { if (user_data) { ((MainWindow*)user_data)->nextMonth(); } return true; } bool prevMonthCallback(GtkAccelGroup *group, GObject *obj, guint keyval, GdkModifierType mod, gpointer user_data) { if (user_data) { ((MainWindow*)user_data)->prevMonth(); } return true; } bool goTodayCallback(GtkAccelGroup *group, GObject *obj, guint keyval, GdkModifierType mod, gpointer user_data) { if (user_data) { ((MainWindow*)user_data)->goToday(); } return true; } MainWindow::MainWindow() { Config* config = Config::getInstance(); widget = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(widget), "gsimplecal"); gtk_window_set_decorated(GTK_WINDOW(widget), config->mainwindow_decorated); gtk_window_set_keep_above(GTK_WINDOW(widget), config->mainwindow_keep_above); gtk_window_set_skip_taskbar_hint(GTK_WINDOW(widget), config->mainwindow_skip_taskbar); gtk_window_set_position(GTK_WINDOW(widget), config->mainwindow_position); if (config->mainwindow_sticky) { gtk_window_stick(GTK_WINDOW(widget)); } // Create box for child items children_box = gtk_vbox_new(false, 10); calendar = NULL; if (config->show_calendar) { calendar = new Calendar(); calendar->addToBox(children_box); } timezones = NULL; if (config->show_timezones) { timezones = new Timezones(); timezones->updateTime(); timezones->addToBox(children_box); } gtk_container_add(GTK_CONTAINER(widget), children_box); gtk_widget_show(children_box); gtk_widget_show(widget); // Connect keyboard accelerators GtkAccelGroup *accelerators = gtk_accel_group_new(); GClosure *closure; Shortcut keys[] = {{GDK_Escape, 0, closeCallback}, {GDK_q, GDK_CONTROL_MASK, closeCallback}, {GDK_w, GDK_CONTROL_MASK, closeCallback}, {GDK_j, GDK_SHIFT_MASK, nextYearCallback}, {GDK_k, GDK_SHIFT_MASK, prevYearCallback}, {GDK_j, 0, nextMonthCallback}, {GDK_k, 0, prevMonthCallback}, {GDK_g, 0, goTodayCallback}, {GDK_Home, 0, goTodayCallback}}; for (int key = 0; key < 9; key++) { closure = g_cclosure_new(G_CALLBACK(keys[key].func), (gpointer)this, NULL); gtk_accel_group_connect(accelerators, keys[key].key, (GdkModifierType)keys[key].modifier, (GtkAccelFlags)NULL, closure); g_closure_unref(closure); } gtk_window_add_accel_group(GTK_WINDOW(widget), accelerators); } MainWindow::~MainWindow() { if (calendar) { delete calendar; } if (timezones) { delete timezones; } gtk_widget_destroy(children_box); gtk_widget_destroy(widget); } GtkWindow* MainWindow::getWindow() { return GTK_WINDOW(widget); } void MainWindow::updateTime() { if (timezones) { timezones->updateTime(); } } void MainWindow::close() { gtk_signal_emit_by_name(GTK_OBJECT(widget), "destroy"); } void MainWindow::goToday() { calendar->goToday(); } void MainWindow::nextMonth() { calendar->nextMonth(); } void MainWindow::prevMonth() { calendar->prevMonth(); } void MainWindow::nextYear() { calendar->nextYear(); } void MainWindow::prevYear() { calendar->prevYear(); } gsimplecal-0.8/src/MainWindow.hpp000064400000000000000000000011511213412122300170400ustar00rootroot00000000000000#ifndef MAINWINDOW_HPP #define MAINWINDOW_HPP #include #include "Calendar.hpp" #include "Timezones.hpp" class MainWindow { public: MainWindow(); ~MainWindow(); GtkWindow* getWindow(); void updateTime(); void close(); void nextMonth(); void prevMonth(); void nextYear(); void prevYear(); void goToday(); Calendar* calendar; protected: GtkWidget* widget; GtkWidget* children_box; Timezones* timezones; }; struct Shortcut { int key; int modifier; bool (*func)(GtkAccelGroup*, GObject*, guint, GdkModifierType, void*); }; #endif gsimplecal-0.8/src/Makefile.am000064400000000000000000000005071213412122300163130ustar00rootroot00000000000000AM_CPPFLAGS = @GTK2_CFLAGS@ LIBS = @GTK2_LIBS@ bin_PROGRAMS = gsimplecal gsimplecal_SOURCES = \ Boxable.cpp \ Boxable.hpp \ Calendar.cpp \ Calendar.hpp \ Clock.cpp \ Clock.hpp \ Config.cpp \ Config.hpp \ gsimplecal.cpp \ MainWindow.cpp \ MainWindow.hpp \ Timezones.cpp \ Timezones.hpp \ Unique.cpp \ Unique.hpp gsimplecal-0.8/src/Timezones.cpp000064400000000000000000000017051213412122300167410ustar00rootroot00000000000000#include #include #include "Config.hpp" #include "Timezones.hpp" #include "Clock.hpp" Timezones::Timezones() { widget = gtk_vbox_new(false, 0); Config* config = Config::getInstance(); for (unsigned int clock_num = 0; clock_num < config->clocks.size(); clock_num++) { Clock* clock = new Clock(config->clocks[clock_num]->label, config->clocks[clock_num]->timezone); clock->addToBox(widget); clocks.push_back(clock); } gtk_widget_show(widget); } Timezones::~Timezones() { for (unsigned int clock_num = 0; clock_num < clocks.size(); clock_num++) { delete clocks[clock_num]; } gtk_widget_destroy(widget); } void Timezones::updateTime() { struct timeval clock_time; gettimeofday(&clock_time, 0); for (unsigned int clock_num = 0; clock_num < clocks.size(); clock_num++) { clocks[clock_num]->updateTime(clock_time); } } gsimplecal-0.8/src/Timezones.hpp000064400000000000000000000004351213412122300167450ustar00rootroot00000000000000#ifndef TIMEZONES_HPP #define TIMEZONES_HPP #include #include #include "Boxable.hpp" #include "Clock.hpp" class Timezones : public Boxable { public: Timezones(); ~Timezones(); void updateTime(); protected: vector clocks; }; #endif gsimplecal-0.8/src/Unique.cpp000064400000000000000000000047031213412122300162330ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include "Unique.hpp" union semun { int val; }; Unique::Unique() { // Get path to the current binary. // It's a bit ugly, I guess, to rely on /proc, but it'll do for now. char szTmp[32]; sprintf(szTmp, "/proc/%d/exe", getpid()); char* filename = new char[PATH_MAX + 1]; int bytes = readlink(szTmp, filename, sizeof(*filename) * PATH_MAX); if (bytes > PATH_MAX - 1) { bytes = PATH_MAX; } filename[bytes] = '\0'; // Get unique key for semaphore. semaphore_key = ftok(filename, 1); if (semaphore_key == -1) { throw new UniqueException("ftok failed"); } delete[] filename; } Unique::~Unique() { } bool Unique::isRunning() { int semid = semget(semaphore_key, 0, 0); if (semid == -1) { return false; } return true; } void Unique::start() { if (!isRunning()) { // Create semaphore; fail if already exists. int semid = semget(semaphore_key, 1, IPC_CREAT | IPC_EXCL | 0660); if (semid == -1) { throw UniqueException("semget failed while creating semaphore"); } // Set initial semaphore value to the current pid, so we could use it to // kill the process from the second instance. union semun semopts; semopts.val = getpid(); if (semctl(semid, 0, SETVAL, semopts) == -1) { throw UniqueException("semctl (SETVAL) failed"); } } } void Unique::signal(int signal_id) { kill(signal_id); } void Unique::kill() { kill(SIGTERM); } void Unique::kill(int signal_id) { if (isRunning()) { // Get semaphore; fail if not present. int semid = semget(semaphore_key, 1, 0660); if (semid == -1) { throw UniqueException("semget failed while trying to kill"); } // Get the pid from semaphore value (stored before) to kill the process. int pid = semctl(semid, 0, GETVAL, 0); if (pid <= 0) { throw UniqueException("semctl (GETVAL) failed"); } if (::kill(pid, signal_id)) { throw UniqueException("kill failed"); } } } void Unique::stop() { int semid = semget(semaphore_key, 1, 0660); if (semid != -1) { semctl(semid, 0, IPC_RMID, 0); } } gsimplecal-0.8/src/Unique.hpp000064400000000000000000000011331213412122300162320ustar00rootroot00000000000000#ifndef UNIQUE_HPP #define UNIQUE_HPP #include #include #include using namespace std; class UniqueException : public exception { public: UniqueException(string m="Unique Exception") : msg(m) {} ~UniqueException() throw() {} const char* what() const throw() { return msg.c_str(); } private: string msg; }; class Unique { public: Unique(); ~Unique(); bool isRunning(); void kill(); void kill(int signal_id); void signal(int signal_id); void start(); void stop(); protected: key_t semaphore_key; }; #endif gsimplecal-0.8/src/gsimplecal.cpp000064400000000000000000000034771213412122300171140ustar00rootroot00000000000000#include #include #include #include #include "MainWindow.hpp" #include "Config.hpp" #include "Unique.hpp" MainWindow* main_window; static void signal_handler(int signal_id) { if (signal_id == SIGTERM) { gtk_main_quit(); } else if (signal_id == SIGUSR1) { main_window->nextMonth(); } else if (signal_id == SIGUSR2) { main_window->prevMonth(); } } static void destroy() { delete main_window; gtk_main_quit(); } static bool time_handler(GtkWidget *widget) { main_window->updateTime(); return true; } int main(int argc, char *argv[]) { Unique* unique = new Unique(); if (unique->isRunning()) { try { if (argc >= 2 && strcmp(argv[1], "next_month") == 0) { unique->signal(SIGUSR1); } else if (argc >= 2 && strcmp(argv[1], "prev_month") == 0) { unique->signal(SIGUSR2); } else { unique->kill(); unique->stop(); } return 0; } catch (UniqueException e) { std::cerr << "Looks like gsimplecal crashed last time." << " Exception message is: " << e.what() << ". Cleaning up." << std::endl; unique->stop(); } } unique->start(); signal(SIGTERM, &signal_handler); signal(SIGUSR1, &signal_handler); signal(SIGUSR2, &signal_handler); gtk_init(&argc, &argv); main_window = new MainWindow(); gtk_signal_connect(GTK_OBJECT(main_window->getWindow()), "destroy", GTK_SIGNAL_FUNC(destroy), NULL); Config* config = Config::getInstance(); if (config->show_timezones) { g_timeout_add(30000, (GSourceFunc)time_handler, NULL); } gtk_main(); unique->stop(); return 0; }