/* Orage - Calendar and alarm handler
*
* Copyright (c) 2005-2008 Juha Kautto (juha at xfce.org)
* Copyright (c) 2003-2006 Mickael Graf (korbinus at xfce.org)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
Free Software Foundation
51 Franklin Street, 5th Floor
Boston, MA 02110-1301 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/stat.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <time.h>
#include <libxfcegui4/libxfcegui4.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#define ORAGE_MAIN "orage"
#include "functions.h"
#include "mainbox.h"
#include "reminder.h"
#include "ical-code.h"
#include "tray_icon.h"
#include "parameters.h"
#include "interface.h"
#ifdef HAVE_DBUS
#include "orage-dbus.h"
#endif
/* session client handler */
static SessionClient *session_client = NULL;
static GdkAtom atom_alive;
static void send_event(char *event)
{
GdkEventClient gev;
Window xwindow;
memset(&gev, 0, sizeof(gev));
xwindow = XGetSelectionOwner(GDK_DISPLAY()
, gdk_x11_atom_to_xatom(atom_alive));
gev.type = GDK_CLIENT_EVENT;
gev.window = NULL;
gev.send_event = TRUE;
gev.message_type = gdk_atom_intern(event, FALSE);
gev.data_format = 8;
gdk_event_send_client_message((GdkEvent *)&gev, (GdkNativeWindow)xwindow);
}
void orage_toggle_visible()
{
send_event("_XFCE_CALENDAR_TOGGLE_HERE");
}
void raise_orage()
{
send_event("_XFCE_CALENDAR_RAISE");
}
gboolean mWindow_delete_event_cb(GtkWidget *widget, GdkEvent *event
, gpointer user_data)
{
orage_toggle_visible();
return(TRUE);
}
static void raise_window()
{
GdkScreen *screen = NULL;
GdkWindow *window;
CalWin *cal = (CalWin *)g_par.xfcal;
/*
screen = xfce_gdk_display_locate_monitor_with_pointer(NULL, NULL);
*/
gtk_window_set_screen(GTK_WINDOW(cal->mWindow)
, screen ? screen : gdk_screen_get_default());
if (g_par.pos_x || g_par.pos_y)
gtk_window_move(GTK_WINDOW(cal->mWindow)
, g_par.pos_x, g_par.pos_y);
if (g_par.select_always_today)
orage_select_today(GTK_CALENDAR(cal->mCalendar));
if (g_par.set_stick)
gtk_window_stick(GTK_WINDOW(cal->mWindow));
gtk_window_set_keep_above(GTK_WINDOW(cal->mWindow)
, g_par.set_ontop);
window = GTK_WIDGET(cal->mWindow)->window;
gdk_x11_window_set_user_time(window, gdk_x11_get_server_time(window));
gtk_window_present(GTK_WINDOW(cal->mWindow));
}
static gboolean client_message_received(GtkWidget *widget
, GdkEventClient *event, gpointer user_data)
{
CalWin *cal = (CalWin *)g_par.xfcal;
if (event->message_type ==
gdk_atom_intern("_XFCE_CALENDAR_RAISE", FALSE)) {
raise_window();
return TRUE;
}
else if (event->message_type ==
gdk_atom_intern("_XFCE_CALENDAR_TOGGLE_HERE", FALSE)) {
if (GTK_WIDGET_VISIBLE(cal->mWindow)) {
write_parameters();
gtk_widget_hide(cal->mWindow);
return TRUE;
}
else {
raise_window();
return TRUE;
}
}
else if (event->message_type ==
gdk_atom_intern("_XFCE_CALENDAR_PREFERENCES", FALSE)) {
show_parameters();
return TRUE;
}
return FALSE;
}
gboolean keep_tidy(void)
{
#ifdef HAVE_ARCHIVE
/* move old appointment to other file to keep the active
calendar file smaller and faster */
xfical_archive();
#endif
return TRUE;
}
/*
* SaveYourself callback
*
* This is called when the session manager requests the client to save its
* state.
*/
void save_yourself_cb(gpointer data, int save_style, gboolean shutdown
, int interact_style, gboolean fast)
{
write_parameters();
}
/*
* Die callback
*
* This is called when the session manager requests the client to go down.
*/
void die_cb(gpointer data)
{
gtk_main_quit();
}
static void print_version(void)
{
g_print(_("\tThis is %s version %s for Xfce %s\n\n")
, PACKAGE, VERSION, xfce_version_string());
g_print(_("\tReleased under the terms of the GNU General Public License.\n"));
g_print(_("\tCompiled against GTK+-%d.%d.%d, ")
, GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION);
g_print(_("using GTK+-%d.%d.%d.\n")
, gtk_major_version, gtk_minor_version, gtk_micro_version);
#ifdef HAVE_DBUS
g_print(_("\tUsing DBUS for import.\n"));
#else
g_print(_("\tNot using DBUS. Import works only partially.\n"));
#endif
#ifdef HAVE_NOTIFY
g_print(_("\tUsing libnotify.\n"));
#else
g_print(_("\tNot using libnotify.\n"));
#endif
#ifdef HAVE_ARCHIVE
g_print(_("\tUsing automatic archving.\n"));
#else
g_print(_("\tNot using archiving.\n"));
#endif
g_print("\n");
}
static void preferences(void)
{
send_event("_XFCE_CALENDAR_RAISE");
send_event("_XFCE_CALENDAR_PREFERENCES");
}
static void print_help(void)
{
g_print(_("Usage: orage [options] [files]\n\n"));
g_print(_("Options:\n"));
g_print(_("--version (-v) \t\tshow version of orage\n"));
g_print(_("--help (-h) \t\tprint this text\n"));
g_print(_("--preferences (-p) \tshow preferences form\n"));
g_print(_("--toggle (-t) \t\tmake orage visible/unvisible\n"));
g_print(_("--add-foreign (-a) file [RW] \tadd a foreign file\n"));
g_print(_("--remove-foreign (-r) file \tremove a foreign file\n"));
g_print("\n");
g_print(_("files=ical files to load into orage\n"));
#ifndef HAVE_DBUS
g_print(_("\tdbus not included in orage. \n"));
g_print(_("\twithout dbus [files] and foreign file options(-a & -r) can only be used when starting orage \n"));
#endif
g_print("\n");
}
static void import_file(gboolean running, char *file_name, gboolean initialized)
{
if (running && !initialized) {
/* let's use dbus since server is running there already */
#ifdef HAVE_DBUS
if (orage_dbus_import_file(file_name))
orage_message(40, "import done file=%s", file_name);
else
g_warning("import failed file=%s\n", file_name);
#else
g_warning("Can not do import without dbus. import failed file=%s\n", file_name);
#endif
}
else if (!running && initialized) {/* do it self directly */
if (xfical_import_file(file_name))
orage_message(40, "import done file=%s", file_name);
else
g_warning("import failed file=%s\n", file_name);
}
}
static void add_foreign(gboolean running, char *file_name, gboolean initialized
, gboolean read_only)
{
if (running && !initialized)
/* let's use dbus since server is running there already */
#ifdef HAVE_DBUS
if (orage_dbus_foreign_add(file_name, read_only))
orage_message(40, "add done foreign file=%s", file_name);
else
g_warning("add failed foreign file=%s\n", file_name);
#else
g_warning("Can not do add foreign file without dbus. failed file=%s\n", file_name);
#endif
else if (!running && initialized) { /* do it self directly */
if (orage_foreign_file_add(file_name, read_only))
orage_message(40, "add done foreign file=%s", file_name);
else
g_warning("add failed foreign file=%s\n", file_name);
}
}
static void remove_foreign(gboolean running, char *file_name, gboolean initialized)
{
if (running && !initialized)
/* let's use dbus since server is running there already */
#ifdef HAVE_DBUS
if (orage_dbus_foreign_remove(file_name))
orage_message(40, "remove done foreign file=%s", file_name);
else
g_warning("remove failed foreign file=%s\n", file_name);
#else
g_warning("Can not do remove foreign file without dbus. failed file=%s\n", file_name);
#endif
else if (!running && initialized) { /* do it self directly */
if (orage_foreign_file_remove(file_name))
orage_message(40, "remove done foreign file=%s", file_name);
else
g_warning("remove failed foreign file=%s\n", file_name);
}
}
static gboolean process_args(int argc, char *argv[], gboolean running
, gboolean initialized)
{
int argi;
gboolean end = FALSE;
gboolean foreign_file_read_only = TRUE;
if (running && argc == 1) { /* no parameters */
raise_orage();
return(TRUE);
}
end = running;
for (argi = 1; argi < argc; argi++) {
if (!strcmp(argv[argi], "--sm-client-id")) {
argi++; /* skip the parameter also */
}
else if (!strcmp(argv[argi], "--version") ||
!strcmp(argv[argi], "-v")) {
print_version();
end = TRUE;
}
else if (!strcmp(argv[argi], "--help") ||
!strcmp(argv[argi], "-h") ||
!strcmp(argv[argi], "-?")) {
print_help();
end = TRUE;
}
else if (!strcmp(argv[argi], "--preferences") ||
!strcmp(argv[argi], "-p")) {
if (running && !initialized) {
preferences();
end = TRUE;
}
else if (!running && initialized) {
preferences();
}
/* if (!running && !initialized) Do nothing
* if (running && initialized) impossible
*/
}
else if (!strcmp(argv[argi], "--toggle") ||
!strcmp(argv[argi], "-t")) {
orage_toggle_visible();
end = TRUE;
}
else if (!strcmp(argv[argi], "--add-foreign") ||
!strcmp(argv[argi], "-a")) {
if (argi+1 >= argc) {
g_print("\nFile not specified\n\n");
print_help();
end = TRUE;
}
else {
if (argi+2 < argc && (
!strcmp(argv[argi+2], "RW") ||
!strcmp(argv[argi+2], "READWRITE"))) {
foreign_file_read_only = FALSE;
}
add_foreign(running, argv[++argi], initialized
, foreign_file_read_only);
if (!foreign_file_read_only)
++argi;
}
}
else if (!strcmp(argv[argi], "--remove-foreign") ||
!strcmp(argv[argi], "-r")) {
if (argi+1 >= argc) {
g_print("\nFile not specified\n\n");
print_help();
end = TRUE;
}
else {
remove_foreign(running, argv[++argi], initialized);
}
}
else if (argv[argi][0] == '-') {
g_print(_("\nUnknown option %s\n\n"), argv[argi]);
print_help();
end = TRUE;
}
else {
import_file(running, argv[argi], initialized);
raise_orage();
}
}
return(end);
}
static gboolean check_orage_alive()
{
Window xwindow;
if ((xwindow = XGetSelectionOwner(GDK_DISPLAY()
, gdk_x11_atom_to_xatom(atom_alive))) != None)
return(TRUE); /* yes, we got selection owner, so orage must be there */
else /* no selction owner, so orage is not running yet */
return(FALSE);
}
static void mark_orage_alive()
{
GtkWidget *hidden;
hidden = gtk_invisible_new();
gtk_widget_show(hidden);
if (!gdk_selection_owner_set(hidden->window, atom_alive
, gdk_x11_get_server_time(hidden->window), FALSE)) {
g_error("Unable acquire ownership of selection");
}
g_signal_connect(hidden, "client-event"
, G_CALLBACK(client_message_received), NULL);
}
int main(int argc, char *argv[])
{
gboolean running, initialized = FALSE;
/* init i18n = nls to use gettext */
bindtextdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
#endif
textdomain(GETTEXT_PACKAGE);
gtk_init(&argc, &argv);
atom_alive = gdk_atom_intern("_XFCE_CALENDAR_RUNNING", FALSE);
running = check_orage_alive();
if (process_args(argc, argv, running, initialized))
return(EXIT_SUCCESS);
/* we need to start since orage was not found to be running already */
mark_orage_alive();
g_par.xfcal = g_new(CalWin, 1);
/* Create the main window */
((CalWin *)g_par.xfcal)->mWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect((gpointer) ((CalWin *)g_par.xfcal)->mWindow, "delete_event"
, G_CALLBACK(mWindow_delete_event_cb), (gpointer)g_par.xfcal);
/*
* try to connect to the session manager
*/
session_client = client_session_new(argc, argv, NULL
, SESSION_RESTART_IF_RUNNING, 50);
session_client->save_yourself = save_yourself_cb;
session_client->die = die_cb;
(void)session_init(session_client);
/*
* Now it's serious, the application is running, so we create the RC
* directory and check for config files in old location.
*/
#ifdef HAVE_DBUS
orage_dbus_start();
#endif
/*
* Create the orage.
*/
read_parameters();
build_mainWin();
set_parameters();
if (g_par.start_visible) {
gtk_widget_show(((CalWin *)g_par.xfcal)->mWindow);
}
else if (g_par.start_minimized) {
gtk_window_iconify(GTK_WINDOW(((CalWin *)g_par.xfcal)->mWindow));
gtk_widget_show(((CalWin *)g_par.xfcal)->mWindow);
}
else { /* hidden */
gtk_widget_realize(((CalWin *)g_par.xfcal)->mWindow);
gtk_widget_hide(((CalWin *)g_par.xfcal)->mWindow);
}
reset_orage_day_change(FALSE); /* first day change after we start */
alarm_read();
mCalendar_month_changed_cb(
(GtkCalendar *)((CalWin *)g_par.xfcal)->mCalendar, NULL);
/* start monitoring foreign file updates if we have foreign files */
if (g_par.foreign_count)
g_timeout_add(30*1000, (GtkFunction)orage_foreign_files_check, NULL);
/* let's check if I got filename as a parameter */
initialized = TRUE;
process_args(argc, argv, running, initialized);
gtk_main();
keep_tidy();
return(EXIT_SUCCESS);
}