Logo Search packages:      
Sourcecode: cairo-clock version File versions

cairo-clock.c

/*******************************************************************************
**3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 
**      10        20        30        40        50        60        70        80
**
** program:
**    cairo-clock
**
** author:
**    Mirco "MacSlow" Mueller <macslow@bangang.de>
**
** created: .
**    10.1.2006 (or so)
**
** last change:
**    1.4.2006
**
** notes:
**    In my ongoing efforts to do something useful while learning the cairo-API
**    I produced this nifty program. Surprisingly it displays the current system
**    time in the old-fashioned way of an analog clock. I place this program
**    under the "GNU General Public License". If you don't know what that means
**    take a look a here...
**
**        http://www.gnu.org/licenses/licenses.html#GPL
**
** todo:
**    clean up code and make it sane to read/understand
**
** supplied patches:
**    26.3.2006 - received a patch to add a 24h-mode from Darryll "Moppsy"
**    Truchan <moppsy@comcast.net>
**
*******************************************************************************/
 
#include <time.h>
#include <math.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include <getopt.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <glade/glade.h>
#include <librsvg/rsvg.h>
#include <librsvg/rsvg-cairo.h>

#if !GTK_CHECK_VERSION(2,9,0)
#include <X11/Xlib.h>
#include <X11/extensions/shape.h>
#include <gdk/gdkx.h>
#endif

#define SECOND_INTERVAL  1000
#define MINUTE_INTERVAL 60000
#define MIN_WIDTH          32
#define MIN_HEIGHT         32
#define MAX_WIDTH         512
#define MAX_HEIGHT        512

typedef enum _LayerElement
{
      CLOCK_DROP_SHADOW = 0,
      CLOCK_FACE,
      CLOCK_MARKS,
      CLOCK_HOUR_HAND_SHADOW,
      CLOCK_MINUTE_HAND_SHADOW,
      CLOCK_SECOND_HAND_SHADOW,
      CLOCK_HOUR_HAND,
      CLOCK_MINUTE_HAND,
      CLOCK_SECOND_HAND,
      CLOCK_FACE_SHADOW,
      CLOCK_GLASS,
      CLOCK_FRAME,
      CLOCK_ELEMENTS
} LayerElement;

typedef enum _SurfaceKind
{
      KIND_BACKGROUND = 0,
      KIND_FOREGROUND
} SurfaceKind;

typedef enum _StartupSizeKind
{
      SIZE_SMALL = 0,
      SIZE_MEDIUM,
      SIZE_LARGE,
      SIZE_CUSTOM
} StartupSizeKind;

typedef struct _ThemeEntry
{
      struct _ThemeEntry* pPrev;
      char* pcName;
      char* pcPath;
      struct _ThemeEntry* pNext;
} ThemeEntry;

/* yeah I know... global variables are the devil */
cairo_t*          g_pMainContext;
RsvgHandle*       g_pSvgHandles[CLOCK_ELEMENTS];
char              g_cFileNames[CLOCK_ELEMENTS][30] =
{
      "clock-drop-shadow.svg",
      "clock-face.svg",
      "clock-marks.svg",
      "clock-hour-hand-shadow.svg",
      "clock-minute-hand-shadow.svg",
      "clock-second-hand-shadow.svg",
      "clock-hour-hand.svg",
      "clock-minute-hand.svg",
      "clock-second-hand.svg",
      "clock-face-shadow.svg",
      "clock-glass.svg",
      "clock-frame.svg"
};
RsvgDimensionData g_DimensionData;
int                           g_iSeconds;
int                           g_iMinutes;
int                           g_iHours;
int                           g_iDay;
int                           g_iMonth;
char                    g_acDate[6];
static time_t           g_timeOfDay;
struct tm*              g_pTime;
int                 g_i24 = 0;      /* make/don't make hour-hand use 24h-display */
int                           g_iShowDate = 0;  /* draw/don't draw date-display */
int                           g_iShowSeconds = 0;     /* draw/don't draw seconds */
int                           g_iDefaultX = -1; /* x-position of top-left corner */
int                           g_iDefaultY = -1; /* ... y-position, < 0 means undefined */
int                           g_iDefaultWidth = 128;  /* window opens with this width */
int                           g_iDefaultHeight = 128; /* ... and with this height */
char                    g_acTheme[80];
int                           g_iKeepOnTop = 0;
int                           g_iAppearInPager = 0;
int                           g_iAppearInTaskbar = 0;
int                           g_iSticky = 0;
GtkWidget*              g_pMainWindow = NULL;
GtkWidget*              g_pPopUpMenu = NULL;
GtkWidget*              g_pSettingsDialog = NULL;
GtkWidget*              g_pInfoDialog = NULL;
GtkWidget*              g_pTableStartupSize = NULL;
GtkWidget*              g_pComboBoxStartupSize = NULL;
GtkWidget*              g_pSpinButtonWidth = NULL;
GtkWidget*              g_pSpinButtonHeight = NULL;
guint                   g_iuIntervalHandlerId;
int                           g_iThemeCounter = 0;
ThemeEntry*             g_pThemeList;
char                    g_acAppName[] = "MacSlow's Cairo-Clock";
char                    g_acAppVersion[] = "0.3.2";
gboolean                g_bNeedsUpdate = TRUE;
cairo_surface_t*  g_pBackgroundSurface = NULL;
cairo_surface_t*  g_pForegroundSurface = NULL;

void render (int width, int height);
void update_input_shape (GtkWidget* pWindow, gint iWidth, gint iHeight);

void draw_background (cairo_t* pDrawingContext, int iWidth, int iHeight)
{
      /* clear context */
      cairo_scale (pDrawingContext,
                         (double) iWidth / (double) g_DimensionData.width,
                         (double) iHeight / (double) g_DimensionData.height);
      cairo_set_source_rgba (pDrawingContext, 1.0f, 1.0f, 1.0f, 0.0f);
      cairo_set_operator (pDrawingContext, CAIRO_OPERATOR_OVER);
      cairo_paint (pDrawingContext);

      /* draw stuff */
      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_DROP_SHADOW], pDrawingContext);
      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_FACE], pDrawingContext);
      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_MARKS], pDrawingContext);
}

void draw_foreground (cairo_t* pDrawingContext, int iWidth, int iHeight)
{
      /* clear context */
      cairo_scale (pDrawingContext,
                         (double) iWidth / (double) g_DimensionData.width,
                         (double) iHeight / (double) g_DimensionData.height);
      cairo_set_source_rgba (pDrawingContext, 1.0f, 1.0f, 1.0f, 0.0f);
      cairo_set_operator (pDrawingContext, CAIRO_OPERATOR_OVER);
      cairo_paint (pDrawingContext);

      /* draw stuff */
      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_FACE_SHADOW], pDrawingContext);
      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_GLASS], pDrawingContext);
      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_FRAME], pDrawingContext);
}

cairo_surface_t* update_surface (cairo_surface_t* pOldSurface,
                                                 cairo_t* pSourceContext,
                                                 int iWidth,
                                                 int iHeight,
                                                 SurfaceKind kind)
{
      cairo_surface_t* pNewSurface = NULL;
      cairo_t* pDrawingContext = NULL;

      cairo_surface_destroy (pOldSurface);
      pNewSurface = cairo_surface_create_similar (cairo_get_target (pSourceContext),
                                                                        CAIRO_CONTENT_COLOR_ALPHA,
                                                                        iWidth,
                                                                        iHeight);
      if (cairo_surface_status (pNewSurface) != CAIRO_STATUS_SUCCESS)
            return NULL;

      pDrawingContext = cairo_create (pNewSurface);
      if (cairo_status (pDrawingContext) != CAIRO_STATUS_SUCCESS)
            return NULL;

      switch (kind)
      {
            case KIND_BACKGROUND :
                  draw_background (pDrawingContext, iWidth, iHeight);
            break;

            case KIND_FOREGROUND :
                  draw_foreground (pDrawingContext, iWidth, iHeight);
            break;
      }

      cairo_destroy (pDrawingContext);

      return pNewSurface;
}

static gboolean time_handler (GtkWidget* pWidget)
{
      gtk_widget_queue_draw (pWidget);
      return TRUE;
}

static gboolean on_expose (GtkWidget*           pWidget,
                                       GdkEventExpose*      pExpose)
{
      static gint iWidth;
      static gint iHeight;

      g_pMainContext = gdk_cairo_create (pWidget->window);
      cairo_set_operator (g_pMainContext, CAIRO_OPERATOR_SOURCE);
      gtk_window_get_size (GTK_WINDOW (pWidget), &iWidth, &iHeight);
      if (g_bNeedsUpdate == TRUE)
      {
            g_pBackgroundSurface = update_surface (g_pBackgroundSurface,
                                                                     g_pMainContext,
                                                                     iWidth,
                                                                     iHeight,
                                                                     KIND_BACKGROUND);
            g_pForegroundSurface = update_surface (g_pForegroundSurface,
                                                                     g_pMainContext,
                                                                     iWidth,
                                                                     iHeight,
                                                                     KIND_FOREGROUND);
            g_bNeedsUpdate = FALSE;
      }
      render (iWidth, iHeight);
      cairo_destroy (g_pMainContext);

      return FALSE;
}

static void on_alpha_screen_changed (GtkWidget* pWidget,
                                                       GdkScreen* pOldScreen,
                                                       GtkWidget* pLabel)
{                       
      GdkScreen* pScreen = gtk_widget_get_screen (pWidget);
      GdkColormap*       pColormap = gdk_screen_get_rgba_colormap (pScreen);
      
      if (!pColormap)
            pColormap = gdk_screen_get_rgb_colormap (pScreen);

      gtk_widget_set_colormap (pWidget, pColormap);
}

gboolean on_key_press (GtkWidget    *     pWidget,
                                 GdkEventKey*   pKey,
                                 gpointer       userData)
{
      if (pKey->type == GDK_KEY_PRESS)
      {
            switch (pKey->keyval)
            {
                  case GDK_Escape :
                        gtk_main_quit ();
                  break;
            }
      }

      return FALSE;
}

gboolean on_button_press (GtkWidget* pWidget,
                                      GdkEventButton* pButton,
                                      GdkWindowEdge edge)
{
      if (pButton->type == GDK_BUTTON_PRESS)
      {
            if (pButton->button == 1)
                  gtk_window_begin_move_drag (GTK_WINDOW (gtk_widget_get_toplevel (pWidget)),
                                                            pButton->button,
                                                            pButton->x_root,
                                                            pButton->y_root,
                                                            pButton->time);

            if (pButton->button == 2)
                  gtk_window_begin_resize_drag (GTK_WINDOW (gtk_widget_get_toplevel (pWidget)),
                                                              edge,
                                                              pButton->button,
                                                              pButton->x_root,
                                                              pButton->y_root,
                                                              pButton->time);

            if (pButton->button == 3)
                  gtk_menu_popup (GTK_MENU (g_pPopUpMenu),
                                          NULL,
                                          NULL,
                                          NULL,
                                          NULL,
                                          pButton->button,
                                          pButton->time);
    }

      return TRUE;
}

void on_settings_activate (GtkMenuItem* pMenuItem, gpointer data)
{
      gtk_widget_show (g_pSettingsDialog);
}

void on_info_activate (GtkMenuItem* pMenuItem, gpointer data)
{
      gtk_widget_show (g_pInfoDialog);
}

void on_quit_activate (GtkMenuItem* pMenuItem, gpointer data)
{
      gtk_main_quit ();
}
                         
void render (int width, int height)
{
      static double fHalfX;
      static double fHalfY;
      static double fShadowOffsetX = -0.75f;
      static double fShadowOffsetY = 0.75f;
      static cairo_text_extents_t textExtents;

      fHalfX = g_DimensionData.width / 2.0f;
      fHalfY = g_DimensionData.height / 2.0f;

      time (&g_timeOfDay);
      g_pTime = localtime (&g_timeOfDay);
      g_iSeconds = g_pTime->tm_sec;
      g_iMinutes = g_pTime->tm_min;
      g_iHours = g_pTime->tm_hour;

      if (!g_i24)
            g_iHours = g_iHours >= 12 ? g_iHours - 12 : g_iHours;

      g_iDay = g_pTime->tm_mday;
      g_iMonth = g_pTime->tm_mon + 1;
      sprintf (g_acDate, "%02d/%02d", g_iDay, g_iMonth);

      cairo_set_operator (g_pMainContext, CAIRO_OPERATOR_SOURCE);

      cairo_set_source_surface (g_pMainContext, g_pBackgroundSurface, 0.0f, 0.0f);
      cairo_paint (g_pMainContext);

      cairo_set_operator (g_pMainContext, CAIRO_OPERATOR_OVER);

      cairo_save (g_pMainContext);
      cairo_scale (g_pMainContext,
                         (double) width / (double) g_DimensionData.width,
                         (double) height / (double) g_DimensionData.height);
      cairo_translate (g_pMainContext, fHalfX, fHalfY);
      cairo_rotate (g_pMainContext, -M_PI/2.0f);

      if (g_iShowDate)
      {
            cairo_save (g_pMainContext);
            cairo_set_source_rgb (g_pMainContext, 1.0f, 0.5f, 0.0f);
            cairo_set_line_width (g_pMainContext, 5.0f);
            cairo_text_extents (g_pMainContext, g_acDate, &textExtents);
            cairo_rotate (g_pMainContext, (M_PI/180.0f) * 90.0f);
            cairo_move_to (g_pMainContext,
                                 -textExtents.width / 2.0f,
                                 2.0f * textExtents.height);
            cairo_show_text (g_pMainContext, g_acDate);
            cairo_restore (g_pMainContext);
      }

      cairo_save (g_pMainContext);
      cairo_translate (g_pMainContext, fShadowOffsetX, fShadowOffsetY);
      cairo_rotate (g_pMainContext,
                          (M_PI/ (g_i24 ? 12.0f : 6.0f)) * g_iHours + (M_PI/(g_i24 ? 720.0f : 360.0f)) * g_iMinutes);

      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_HOUR_HAND_SHADOW], g_pMainContext);

      cairo_restore (g_pMainContext);

      cairo_save (g_pMainContext);
      cairo_translate (g_pMainContext, fShadowOffsetX, fShadowOffsetY);
      cairo_rotate (g_pMainContext, (M_PI/30.0f) * g_iMinutes);

      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_MINUTE_HAND_SHADOW], g_pMainContext);

      cairo_restore (g_pMainContext);

      if (g_iShowSeconds)
      {
            cairo_save (g_pMainContext);
            cairo_translate (g_pMainContext, fShadowOffsetX, fShadowOffsetY);
            cairo_rotate (g_pMainContext, (M_PI/30.0f) * g_iSeconds);

            rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_SECOND_HAND_SHADOW], g_pMainContext);

            cairo_restore (g_pMainContext);
      }

      cairo_save (g_pMainContext);
      cairo_rotate (g_pMainContext,
                          (M_PI/ (g_i24 ? 12.0f : 6.0f)) * g_iHours + (M_PI/(g_i24 ? 720.0f : 360.0f)) * g_iMinutes);

      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_HOUR_HAND], g_pMainContext);

      cairo_restore (g_pMainContext);

      cairo_save (g_pMainContext);
      cairo_rotate (g_pMainContext, (M_PI/30.0f) * g_iMinutes);

      rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_MINUTE_HAND], g_pMainContext);

      cairo_restore (g_pMainContext);

      if (g_iShowSeconds)
      {
            cairo_save (g_pMainContext);
            cairo_rotate (g_pMainContext, (M_PI/30.0f) * g_iSeconds);

            rsvg_handle_render_cairo (g_pSvgHandles[CLOCK_SECOND_HAND], g_pMainContext);
            cairo_restore (g_pMainContext);
      }

      cairo_restore (g_pMainContext);

      cairo_set_source_surface (g_pMainContext, g_pForegroundSurface, 0.0f, 0.0f);
      cairo_paint (g_pMainContext);
}

void on_startup_size_changed (GtkComboBox* pComboBox, gpointer window)
{
      switch (gtk_combo_box_get_active (pComboBox))
      {
            case SIZE_SMALL :
                  gtk_widget_set_sensitive (g_pTableStartupSize, FALSE);
                  gtk_window_resize (GTK_WINDOW (window), 64, 64);
            break;

            case SIZE_MEDIUM :
                  gtk_widget_set_sensitive (g_pTableStartupSize, FALSE);
                  gtk_window_resize (GTK_WINDOW (window), 128, 128);
            break;

            case SIZE_LARGE :
                  gtk_widget_set_sensitive (g_pTableStartupSize, FALSE);
                  gtk_window_resize (GTK_WINDOW (window), 256, 256);
            break;

            case SIZE_CUSTOM :
                  gtk_widget_set_sensitive (g_pTableStartupSize, TRUE);
                  gtk_window_resize (GTK_WINDOW (window),
                                             gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (g_pSpinButtonWidth)),
                                             gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (g_pSpinButtonHeight)));
            break;
      }

      g_bNeedsUpdate = TRUE;
}

void on_height_value_changed (GtkSpinButton* pSpinButton, gpointer window)
{
      gint iWidth;
      gint iOldHeight;
      gint iNewHeight;

      g_bNeedsUpdate = TRUE;
      gtk_window_get_size (GTK_WINDOW (window), &iWidth, &iOldHeight);
      iNewHeight = gtk_spin_button_get_value_as_int (pSpinButton);

      if (iOldHeight != iNewHeight)
      {
            gtk_window_resize (GTK_WINDOW (window), iWidth, iNewHeight);
            gtk_widget_queue_draw (GTK_WIDGET (window));
      }
}

void on_width_value_changed (GtkSpinButton* pSpinButton, gpointer window)
{
      gint iOldWidth;
      gint iNewWidth;
      gint iHeight;

      g_bNeedsUpdate = TRUE;
      gtk_window_get_size (GTK_WINDOW (window), &iOldWidth, &iHeight);
      iNewWidth = gtk_spin_button_get_value_as_int (pSpinButton);

      if (iOldWidth != iNewWidth)
      {
            gtk_window_resize (GTK_WINDOW (window), iNewWidth, iHeight);
            gtk_widget_queue_draw (GTK_WIDGET (window));
      }
}

void on_seconds_toggled (GtkToggleButton* pTogglebutton, gpointer window)
{
      if (gtk_toggle_button_get_active (pTogglebutton))
      {
            g_iShowSeconds = 1;
            g_source_remove (g_iuIntervalHandlerId);
            g_iuIntervalHandlerId = g_timeout_add (SECOND_INTERVAL,
                                                                     (GSourceFunc) time_handler,
                                                                     (gpointer) window);
      }
      else
      {
            g_iShowSeconds = 0;
            g_source_remove (g_iuIntervalHandlerId);
            g_iuIntervalHandlerId = g_timeout_add (MINUTE_INTERVAL,
                                                                     (GSourceFunc) time_handler,
                                                                     (gpointer) window);
      }

      gtk_widget_queue_draw (GTK_WIDGET (window));
}

void on_date_toggled (GtkToggleButton* pTogglebutton, gpointer window)
{
      if (gtk_toggle_button_get_active (pTogglebutton))
            g_iShowDate = 1;
      else
            g_iShowDate = 0;

      gtk_widget_queue_draw (GTK_WIDGET (window));
}

void on_keep_on_top_toggled (GtkToggleButton* pTogglebutton, gpointer window)
{
      if (gtk_toggle_button_get_active (pTogglebutton))
            g_iKeepOnTop = 1;
      else
            g_iKeepOnTop = 0;

      gtk_window_set_keep_above (GTK_WINDOW (window), g_iKeepOnTop);
}

void on_appear_in_pager_toggled (GtkToggleButton* pTogglebutton, gpointer window)
{
      if (gtk_toggle_button_get_active (pTogglebutton))
            g_iAppearInPager = 1;
      else
            g_iAppearInPager = 0;

      gtk_window_set_skip_pager_hint (GTK_WINDOW (window), !g_iAppearInPager);
}

void on_appear_in_taskbar_toggled (GtkToggleButton* pTogglebutton, gpointer window)
{
      if (gtk_toggle_button_get_active (pTogglebutton))
            g_iAppearInTaskbar = 1;
      else
            g_iAppearInTaskbar = 0;

      gtk_window_set_skip_taskbar_hint (GTK_WINDOW (window), !g_iAppearInTaskbar);
}

void on_sticky_toggled (GtkToggleButton* pTogglebutton, gpointer window)
{
      if (gtk_toggle_button_get_active (pTogglebutton))
      {
            g_iSticky = 1;
            gtk_window_stick   (GTK_WINDOW (window));
      }
      else
      {
            g_iSticky = 0;
            gtk_window_unstick (GTK_WINDOW (window));
      }
}

void on_24h_toggled (GtkToggleButton* pTogglebutton, gpointer window)
{
      if (gtk_toggle_button_get_active (pTogglebutton))
            g_i24 = 1;
      else
            g_i24 = 0;
}

void on_help_clicked (GtkButton* pButton, gpointer data)
{
}

char* get_preferences_filename (void)
{
      char* pcFilename = NULL;
      int iLength;

      iLength = strlen (g_get_home_dir ());
      iLength += strlen (".cairo-clockrc");
      iLength += 2;

      pcFilename = (char*) calloc (sizeof (char), iLength);
      if (!pcFilename)
            return NULL;

      strcpy (pcFilename, (char*) g_get_home_dir ());
      strcat (pcFilename, "/");
      strcat (pcFilename, ".cairo-clockrc");

      return pcFilename;
}

gboolean read_settings (char* pcFilePath,
                                    int* piX,
                                    int* piY,
                                    int* piWidth,
                                    int* piHeight,
                                    int* piShowSeconds,
                                    int* piShowDate,
                                    char* pcTheme,
                                    int* piKeepOnTop,
                                    int* piAppearInPager,
                                    int* piAppearInTaskbar,
                                    int* piSticky,
                        int* pi24)
{
      FILE* fileHandle = NULL;
      char cCommentLine[80];

      if (!pcFilePath)
            return FALSE;

      fileHandle = fopen (pcFilePath, "r");
      if (!fileHandle)
            return FALSE;

      fgets (cCommentLine, 80, fileHandle);
      fscanf (fileHandle, "x=%d\n", piX);
      fscanf (fileHandle, "y=%d\n", piY);
      fscanf (fileHandle, "width=%d\n", piWidth);
      fscanf (fileHandle, "height=%d\n", piHeight);
      fscanf (fileHandle, "show-seconds=%d\n", piShowSeconds);
      fscanf (fileHandle, "show-date=%d\n", piShowDate);
      fscanf (fileHandle, "theme=%s\n", pcTheme);
      fscanf (fileHandle, "keep-on-top=%d\n", piKeepOnTop);
      fscanf (fileHandle, "appear-in-pager=%d\n", piAppearInPager);
      fscanf (fileHandle, "appear-in-taskbar=%d\n", piAppearInTaskbar);
      fscanf (fileHandle, "sticky=%d\n", piSticky);
    fscanf (fileHandle, "twentyfour=%d\n", pi24);

      fclose (fileHandle);

      return TRUE;
}

gboolean write_settings (char* pcFilePath,
                                     int iX,
                                     int iY,
                                     int iWidth,
                                     int iHeight,
                                     int iShowSeconds,
                                     int iShowDate,
                                     char* pcTheme,
                                     int iKeepOnTop,
                                     int iAppearInPager,
                                     int iAppearInTaskbar,
                                     int iSticky,
                         int i24)

{
      FILE* fileHandle = NULL;

      if (!pcFilePath)
            return FALSE;

      fileHandle = fopen (pcFilePath, "w");
      if (!fileHandle)
            return FALSE;

      fprintf (fileHandle, "%s %s %s\n", "# This file is machine-generated.",
                                                         "Do not edit it manually!",
                                                         "I really mean it!!!");
      fprintf (fileHandle, "x=%d\n", iX);
      fprintf (fileHandle, "y=%d\n", iY);
      fprintf (fileHandle, "width=%d\n", iWidth);
      fprintf (fileHandle, "height=%d\n", iHeight);
      fprintf (fileHandle, "show-seconds=%d\n", iShowSeconds);
      fprintf (fileHandle, "show-date=%d\n", iShowDate);
      fprintf (fileHandle, "theme=%s\n", pcTheme);
      fprintf (fileHandle, "keep-on-top=%d\n", iKeepOnTop);
      fprintf (fileHandle, "appear-in-pager=%d\n", iAppearInPager);
      fprintf (fileHandle, "appear-in-taskbar=%d\n", iAppearInTaskbar);
      fprintf (fileHandle, "sticky=%d\n", iSticky);
    fprintf (fileHandle, "twentyfour=%d\n", i24);

      fclose (fileHandle);

      return TRUE;
}

void on_close_clicked (GtkButton* pButton, gpointer data)
{
      char* pcFilename = NULL;

      gtk_widget_hide (g_pSettingsDialog);

      pcFilename = get_preferences_filename ();
      if (!write_settings (pcFilename,
                                     g_iDefaultX,
                                     g_iDefaultY,
                                     g_iDefaultWidth,
                                     g_iDefaultHeight,
                                     g_iShowSeconds,
                                     g_iShowDate,
                                     g_acTheme,
                                     g_iKeepOnTop,
                                     g_iAppearInPager,
                                     g_iAppearInTaskbar,
                                     g_iSticky,
                         g_i24))
      {
            printf ("Ups, there was an error while trying to save the preferences!\n");
      }

      if (pcFilename)
            free (pcFilename);
}

ThemeEntry* theme_list_get_first (ThemeEntry* pEntry)
{
      ThemeEntry* pSomeEntry = pEntry;

      if (!pSomeEntry)
            return NULL;

      while (pSomeEntry->pPrev)
            pSomeEntry = pSomeEntry->pPrev;

      return pSomeEntry;
}

ThemeEntry* theme_list_get_last (ThemeEntry* pEntry)
{
      ThemeEntry* pSomeEntry = pEntry;

      if (!pSomeEntry)
            return NULL;

      while (pSomeEntry->pNext)
            pSomeEntry = pSomeEntry->pNext;

      return pSomeEntry;
}

ThemeEntry* theme_entry_get_next (ThemeEntry* pEntry)
{
      if (!pEntry)
            return NULL;

      return pEntry->pNext;
}

ThemeEntry* theme_entry_get_prev (ThemeEntry* pEntry)
{
      if (!pEntry)
            return NULL;

      return pEntry->pPrev;
}

ThemeEntry* theme_entry_new (char* pcName, char* pcPath)
{
      ThemeEntry* pEntry = NULL;

      if (!pcName || !pcPath)
            return NULL;

      pEntry = (ThemeEntry*) calloc (sizeof (ThemeEntry), 1);
      if (!pEntry)
            return NULL;

      pEntry->pcName = (char*) calloc (sizeof (char), strlen (pcName) + 1);
      if (!pEntry->pcName)
      {
            free (pEntry);
            return NULL;
      }
      strcpy (pEntry->pcName, pcName);

      pEntry->pcPath = (char*) calloc (sizeof (char), strlen (pcPath) + 1);
      if (!pEntry->pcPath)
      {
            free (pEntry->pcName);
            free (pEntry);
            return NULL;
      }
      strcpy (pEntry->pcPath, pcPath);

      return pEntry;
}

void theme_entry_delete (ThemeEntry* pSomeEntry)
{
      if (!pSomeEntry)
            return;

      free (pSomeEntry->pcName);
      free (pSomeEntry->pcPath);
      free (pSomeEntry);      
}

void theme_entry_append (ThemeEntry* pThemeList, ThemeEntry* pNewEntry)
{
      ThemeEntry* pLastEntry = NULL;

      if (!pThemeList || !pNewEntry)
            return;

      pLastEntry = theme_list_get_last (pThemeList);
      if (!pLastEntry)
            return;

      pLastEntry->pNext = pNewEntry;
      pNewEntry->pPrev = pLastEntry;
}

void theme_list_delete (ThemeEntry* pEntry)
{
      ThemeEntry* pSomeEntry = pEntry;
      ThemeEntry* pListHead = NULL;

      if (!pSomeEntry)
            return;

      pListHead = theme_list_get_first (pSomeEntry);

      while (pListHead != theme_list_get_last (pListHead))
      {
            pSomeEntry = theme_list_get_last (pListHead);
            pSomeEntry->pPrev->pNext = NULL;
            theme_entry_delete (pSomeEntry);
      }

      theme_entry_delete (pListHead);
}

ThemeEntry* get_theme_list (char* pcSystemPath, char* pcUserPath)
{
      GDir* pThemeDir = NULL;
      char* pcThemeName = NULL;
      ThemeEntry* pThemeListHead = NULL;

      pThemeDir = g_dir_open (pcSystemPath, 0, NULL);
      if (!pThemeDir)
            return NULL;

      do
      {
            pcThemeName = (char*) g_dir_read_name (pThemeDir);
            if (pcThemeName)
            {
                  if (!pThemeListHead)
                        pThemeListHead = theme_entry_new (pcThemeName, pcSystemPath);
                  else
                  {
                        theme_entry_append (pThemeListHead,
                                                      theme_entry_new (pcThemeName,
                                                                               pcSystemPath));
                  }
            }
      } while (pcThemeName);
      g_dir_close (pThemeDir);

      pThemeDir = g_dir_open (pcUserPath, 0, NULL);
      if (!pThemeDir)
            return pThemeListHead;
      do
      {
            pcThemeName = (char*) g_dir_read_name (pThemeDir);
            if (pcThemeName)
            {
                  if (!pThemeListHead)
                        pThemeListHead = theme_entry_new (pcThemeName, pcUserPath);
                  else
                  {
                        theme_entry_append (pThemeListHead,
                                                      theme_entry_new (pcThemeName,
                                                                               pcUserPath));
                  }
            }
      } while (pcThemeName);
      g_dir_close (pThemeDir);

      return pThemeListHead;
}

ThemeEntry* theme_list_get_entry_by_index (ThemeEntry* pThemeList,
                                                               int iThemeIndex)
{
      ThemeEntry* pListHead = NULL;
      ThemeEntry* pThemeEntry = NULL;
      int iIndex = 0;

      if (!pThemeList)
            return NULL;

      pListHead = theme_list_get_first (pThemeList);
      pThemeEntry = pListHead;
      while (iIndex < iThemeIndex)
      {
            pThemeEntry = theme_entry_get_next (pThemeEntry);
            iIndex++;
      }

      return pThemeEntry;
}

void change_theme (ThemeEntry* pThemeList, int iThemeIndex, GtkWidget* window)
{
      ThemeEntry* pTheme = NULL;
      char* pcFullFilename = NULL;
      int iElement = 0;
      GError* pError = NULL;

      if (!pThemeList)
            return;

      pTheme = theme_list_get_entry_by_index (pThemeList, iThemeIndex);
      if (!pTheme)
            return;

      if (window)
            for (iElement = 0; iElement < CLOCK_ELEMENTS; iElement++)
                  rsvg_handle_free (g_pSvgHandles[iElement]);

      for (iElement = 0; iElement < CLOCK_ELEMENTS; iElement++)
      {
            pcFullFilename = (char*) calloc (sizeof (char*),
                                                             strlen (pTheme->pcPath) +
                                                             strlen (pTheme->pcName) +
                                                             strlen (g_cFileNames[iElement])
                                                             + 3);
            strcpy (pcFullFilename, pTheme->pcPath);
            strcat (pcFullFilename, "/");
            strcat (pcFullFilename, pTheme->pcName);
            strcat (pcFullFilename, "/");
            strcat (pcFullFilename, g_cFileNames[iElement]);
            g_pSvgHandles[iElement] = rsvg_handle_new_from_file (pcFullFilename,
                                                                                           &pError);
            free (pcFullFilename);
      }

      if (window)
            gtk_widget_queue_draw (window);
}

void print_theme_list (void)
{
      ThemeEntry* pThemeEntry = NULL;

      if (g_pThemeList)
      {
            pThemeEntry = g_pThemeList;
            while (pThemeEntry)
            {
                  printf ("%s (%s)\n", pThemeEntry->pcName, pThemeEntry->pcPath);
                  pThemeEntry = theme_entry_get_next (pThemeEntry);
            }
      }
}

void on_theme_changed (GtkComboBox* pComboBox, gpointer data)
{
      g_bNeedsUpdate = TRUE;
      sprintf (g_acTheme, "%s", gtk_combo_box_get_active_text (pComboBox));
      change_theme (g_pThemeList,
                          gtk_combo_box_get_active (pComboBox),
                          GTK_WIDGET (data));
      update_input_shape (GTK_WIDGET (data), g_iDefaultWidth, g_iDefaultHeight);
}

gboolean on_configure (GtkWidget* pWidget,
                                 GdkEventConfigure* pEvent,
                                 gpointer data)
{
      gint iNewWidth = pEvent->width;
      gint iNewHeight = pEvent->height;

      if (iNewWidth != g_iDefaultWidth || iNewHeight != g_iDefaultHeight)
      {
            g_bNeedsUpdate = TRUE;
            update_input_shape (pWidget, iNewWidth, iNewHeight);
            g_iDefaultWidth = iNewWidth;
            g_iDefaultHeight = iNewHeight;
      }

      return FALSE;
}

char* get_system_theme_path (void)
{
      return PKGDATA_DIR "/themes";
}

char* get_user_theme_path (void)
{
      char* pcFilename = NULL;
      int iLength;

      iLength = strlen (g_get_home_dir ());
      iLength += strlen (".cairo-clock/themes");
      iLength += 2;

      pcFilename = (char*) calloc (sizeof (char), iLength);
      if (!pcFilename)
            return NULL;

      strcpy (pcFilename, (char*) g_get_home_dir ());
      strcat (pcFilename, "/");
      strcat (pcFilename, ".cairo-clock/themes");

      return pcFilename;
}

char* get_glade_filename (void)
{
      return PKGDATA_DIR "/glade/cairo-clock.glade";
}

char* get_icon_filename (void)
{
      return DATA_DIR "/pixmaps/cairo-clock.png";
}

char* get_logo_filename (void)
{
      return PKGDATA_DIR "/pixmaps/cairo-clock-logo.png";
}

#if !GTK_CHECK_VERSION(2,9,0)
/* this is piece by piece taken from gtk+ 2.9.0 (CVS-head with a patch applied
regarding XShape's input-masks) so people without gtk+ >= 2.9.0 can compile and
run input_shape_test.c */
void do_shape_combine_mask (GdkWindow* window,
                                          GdkBitmap* mask,
                                          gint x,
                                          gint y)
{
      Pixmap pixmap;
      int ignore;
      int maj;
      int min;

      if (!XShapeQueryExtension (GDK_WINDOW_XDISPLAY (window), &ignore, &ignore))
            return;

      if (!XShapeQueryVersion (GDK_WINDOW_XDISPLAY (window), &maj, &min))
            return;

      /* for shaped input we need at least XShape 1.1 */
      if (maj != 1 && min < 1)
            return;

      if (mask)
            pixmap = GDK_DRAWABLE_XID (mask);
      else
      {
            x = 0;
            y = 0;
            pixmap = None;
      }

      XShapeCombineMask (GDK_WINDOW_XDISPLAY (window),
                                 GDK_DRAWABLE_XID (window),
                                 ShapeInput,
                                 x,
                                 y,
                                 pixmap,
                                 ShapeSet);
}
#endif

void update_input_shape (GtkWidget* pWindow, gint iWidth, gint iHeight)
{
      GdkBitmap* pShapeBitmap = NULL;
      cairo_t* pCairoContext = NULL;

      pShapeBitmap = (GdkBitmap*) gdk_pixmap_new (NULL, iWidth, iHeight, 1);
      if (pShapeBitmap)
      {
            pCairoContext = gdk_cairo_create (pShapeBitmap);
            if (cairo_status (pCairoContext) == CAIRO_STATUS_SUCCESS)
            {
                  /* use drop-shadow, clock-face and marks as "clickable" areas */
                  draw_background (pCairoContext, iWidth, iHeight);
                  cairo_destroy (pCairoContext);
#if !GTK_CHECK_VERSION(2,9,0)
                  do_shape_combine_mask (pWindow->window, NULL, 0, 0);
                  do_shape_combine_mask (pWindow->window, pShapeBitmap, 0, 0);
#else
                  gtk_widget_input_shape_combine_mask (pWindow, NULL, 0, 0);
                  gtk_widget_input_shape_combine_mask (pWindow, pShapeBitmap, 0, 0);
#endif
            }
            g_object_unref ((gpointer) pShapeBitmap);
      }
}

void print_usage (void)
{
      printf ("usage: cairo-clock [-options ...]\n");
      printf ("options:\n");
      printf ("    -x, --xposition X     x-position of the top-left window-corner\n");
      printf ("    -y, --yposition Y     y-position of the top-left window-corner\n");
      printf ("    -w, --width WIDTH     open window with this width\n");
      printf ("    -g, --height HEIGHT   open window with this height\n");
      printf ("    -s, --seconds         draw seconds hand\n");
      printf ("    -d, --date            draw data-display\n");
      printf ("    -l, --list            list installed themes and exit\n");
      printf ("    -t, --theme NAME      theme to draw the clock with\n");
      printf ("    -o, --ontop           clock-window stays on top of all windows\n");
      printf ("    -p, --pager           clock-window shows up in pager\n");
      printf ("    -b, --taskbar         clock-window shows up in taskbar\n");
      printf ("    -i, --sticky          clock-window sticks to all workspaces\n");
    printf ("    -e, --twelve          hands work in 12 hour mode\n");
    printf ("    -f, --twentyfour      hands work in 24 hour mode\n");
      printf ("    -h, --help            print this usage-description and exit\n");
      printf ("    -v, --version         print version of program and exit\n");
}

int main (int argc, char **argv)
{
      GdkGeometry hints;
      int iElement;
      GladeXML* pGladeXml;
      GtkWidget* pSettingsMenuItem = NULL;
      GtkWidget* pInfoMenuItem = NULL;
      GtkWidget* pQuitMenuItem = NULL;
      GtkWidget* pComboBoxTheme = NULL;
      GtkWidget* pCheckButtonSeconds = NULL;
      GtkWidget* pCheckButtonDate = NULL;
      GtkWidget* pCheckButtonKeepOnTop = NULL;
      GtkWidget* pCheckButtonAppearInPager = NULL;
      GtkWidget* pCheckButtonAppearInTaskbar = NULL;
      GtkWidget* pCheckButtonSticky = NULL;
      GtkWidget* pCheckButton24h = NULL;
      GtkWidget* pButtonHelp = NULL;
      GtkWidget* pButtonClose = NULL;
      ThemeEntry* pThemeEntry = NULL;
      char* pcFilename = NULL;
      GError* pError = NULL;
      int iCurrentOption = 0;
      int iOptionIndex = 0;
      int iTmp;
      static struct option aOptions[] = {
            {"xposition",     1, NULL, 'x'},
            {"yposition",     1, NULL, 'y'},
            {"width",         1, NULL, 'w'},
            {"height",        1, NULL, 'g'},
            {"seconds",       0, NULL, 's'},
            {"date",          0, NULL, 'd'},
            {"list",          0, NULL, 'l'},
            {"theme",         1, NULL, 't'},
            {"ontop",         0, NULL, 'o'},
            {"pager",         0, NULL, 'p'},
            {"taskbar",       0, NULL, 'b'},
            {"sticky",        0, NULL, 'i'},
        {"twelve",          0, NULL, 'e'},
        {"twentyfour",  0, NULL, 'f'},
            {"help",          0, NULL, 'h'},
            {"version",       0, NULL, 'v'},
            {0,0,0,0}
      };

      /* read in names of all installed themes */
      pcFilename = get_user_theme_path ();
      g_pThemeList = get_theme_list (get_system_theme_path (),
                                                   pcFilename);
      if (pcFilename)
            free (pcFilename);

      bzero (g_acTheme, 80);
      strcpy (g_acTheme, "default");

      gtk_init (&argc, &argv);

      /* options set on the commandline overrule any previous stored settings */
      if (argc > 1)
      {
            while ((iCurrentOption = getopt_long (argc,
                                                                    argv,
                                                                    "x:y:w:g:sdlt:opbiefhv",
                                                                    aOptions,
                                                                    &iOptionIndex)) != -1)
            {
                  switch (iCurrentOption)
                  {
                        case 'x':
                              iTmp = atoi (optarg);
                              if (iTmp >= 0 && iTmp <= gdk_screen_get_width (gdk_screen_get_default ()))
                                    g_iDefaultX = iTmp;
                        break;

                        case 'y':
                              iTmp = atoi (optarg);
                              if (iTmp >= 0 && iTmp <= gdk_screen_get_height (gdk_screen_get_default ()))
                                    g_iDefaultY = iTmp;
                        break;

                        case 'w':
                              iTmp = atoi (optarg);
                              if (iTmp >= MIN_WIDTH && iTmp <= MAX_WIDTH)
                                    g_iDefaultWidth = iTmp;
                        break;

                        case 'g':
                              iTmp = atoi (optarg);
                              if (iTmp >= MIN_HEIGHT && iTmp <= MAX_HEIGHT)
                                    g_iDefaultHeight = iTmp;
                        break;

                        case 's':
                              g_iShowSeconds = 1;
                        break;

                        case 'd':
                              g_iShowDate = 1;
                        break;

                        case 'l':
                              print_theme_list ();
                              exit (0);
                        break;

                        case 't':
                              strcpy (g_acTheme, optarg);
                        break;

                        case 'o':
                              g_iKeepOnTop = 1;
                        break;

                        case 'p':
                              g_iAppearInPager = 1;
                        break;

                        case 'b':
                              g_iAppearInTaskbar = 1;
                        break;

                        case 'i':
                              g_iSticky = 1;
                        break;

                case 'e':
                              g_i24 = 0;
                        break;
                
                        case 'f':
                              g_i24 = 1;
                        break;
                
                        case 'h':
                              print_usage ();
                              exit (0);
                        break;

                        case 'v':
                              printf ("%s %s\n", g_acAppName, g_acAppVersion);
                              exit (0);
                        break;
                  }
            }
      }
      /* just read the previously stored settings */
      else
      {
            pcFilename = get_preferences_filename ();
            read_settings (pcFilename,
                                 &g_iDefaultX,
                                 &g_iDefaultY,
                                 &g_iDefaultWidth,
                                 &g_iDefaultHeight,
                                 &g_iShowSeconds,
                                 &g_iShowDate,
                                 g_acTheme,
                                 &g_iKeepOnTop,
                                 &g_iAppearInPager,
                                 &g_iAppearInTaskbar,
                                 &g_iSticky,
                       &g_i24);

            if (pcFilename)
                  free (pcFilename);
      }

      rsvg_init ();
      pGladeXml = glade_xml_new (get_glade_filename (), NULL, NULL);
      if (!pGladeXml)
      {
            printf ("Could not load \"%s\"!\n", get_glade_filename ());
            exit (1);
      }

      g_pMainWindow = glade_xml_get_widget (pGladeXml, "mainWindow");
      g_pPopUpMenu = glade_xml_get_widget (pGladeXml, "popUpMenu");
      pSettingsMenuItem = glade_xml_get_widget (pGladeXml, "settingsMenuItem");
      pInfoMenuItem = glade_xml_get_widget (pGladeXml, "infoMenuItem");
      pQuitMenuItem = glade_xml_get_widget (pGladeXml, "quitMenuItem");
      g_pSettingsDialog = glade_xml_get_widget (pGladeXml, "settingsDialog");
      gtk_window_set_icon_from_file (GTK_WINDOW (g_pSettingsDialog),
                                                   get_icon_filename (),
                                                   NULL);
      g_pInfoDialog = glade_xml_get_widget (pGladeXml, "infoDialog");
      gtk_window_set_icon_from_file (GTK_WINDOW (g_pInfoDialog),
                                                   get_icon_filename (),
                                                   NULL);
      gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (g_pInfoDialog),
                                                  g_acAppVersion);
      gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (g_pInfoDialog),
                                             gdk_pixbuf_new_from_file (get_logo_filename (),
                                             &pError));
      g_pComboBoxStartupSize = glade_xml_get_widget (pGladeXml,
                                                                           "comboboxStartupSize");
      g_pTableStartupSize = glade_xml_get_widget (pGladeXml, "tableStartupSize");
      g_pSpinButtonWidth = glade_xml_get_widget (pGladeXml, "spinbuttonWidth");
      g_pSpinButtonHeight = glade_xml_get_widget (pGladeXml, "spinbuttonHeight");
      pComboBoxTheme = glade_xml_get_widget (pGladeXml, "comboboxTheme");
      pCheckButtonSeconds = glade_xml_get_widget (pGladeXml,
                                                                        "checkbuttonSeconds");
      pCheckButtonDate = glade_xml_get_widget (pGladeXml, "checkbuttonDate");
      pCheckButtonKeepOnTop = glade_xml_get_widget (pGladeXml,
                                                                          "checkbuttonKeepOnTop");
      pCheckButtonAppearInPager = glade_xml_get_widget (pGladeXml,
                                                                                "checkbuttonAppearInPager");
      pCheckButtonAppearInTaskbar = glade_xml_get_widget (pGladeXml,
                                                                                    "checkbuttonAppearInTaskbar");
      pCheckButtonSticky = glade_xml_get_widget (pGladeXml, "checkbuttonSticky");
      pCheckButton24h = glade_xml_get_widget (pGladeXml, "checkbutton24h");
      pButtonHelp = glade_xml_get_widget (pGladeXml, "buttonHelp");
      pButtonClose = glade_xml_get_widget (pGladeXml, "buttonClose");

      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pCheckButtonSeconds),
                                                  g_iShowSeconds);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pCheckButtonDate),
                                                  g_iShowDate);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pCheckButtonKeepOnTop),
                                                  g_iKeepOnTop);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pCheckButtonAppearInPager),
                                                  g_iAppearInPager);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pCheckButtonAppearInTaskbar),
                                                  g_iAppearInTaskbar);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pCheckButtonSticky),
                                                  g_iSticky);
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pCheckButton24h),
                                                  g_i24);

      if (g_pThemeList)
      {
            pThemeEntry = g_pThemeList;
            while (pThemeEntry)
            {
                  gtk_combo_box_append_text (GTK_COMBO_BOX (pComboBoxTheme),
                                                         (gchar*) pThemeEntry->pcName);
                  if (!strcmp (g_acTheme, pThemeEntry->pcName))
                  {
                        gtk_combo_box_set_active (GTK_COMBO_BOX (pComboBoxTheme),
                                                              g_iThemeCounter);
                        change_theme (pThemeEntry, g_iThemeCounter, NULL);
                  }
                  g_iThemeCounter++;
                  pThemeEntry = theme_entry_get_next (pThemeEntry);
            }
      }

      rsvg_handle_get_dimensions (g_pSvgHandles[CLOCK_DROP_SHADOW],
                                                &g_DimensionData);

      gtk_window_set_decorated (GTK_WINDOW (g_pMainWindow), FALSE);
      gtk_window_set_resizable (GTK_WINDOW (g_pMainWindow), TRUE);
      gtk_widget_set_app_paintable (g_pMainWindow, TRUE);
      gtk_window_set_icon_from_file (GTK_WINDOW (g_pMainWindow),
                                                   get_icon_filename (),
                                                   NULL);
      gtk_window_set_title (GTK_WINDOW (g_pMainWindow), "MacSlow's Cairo-Clock");
      gtk_window_set_default_size (GTK_WINDOW (g_pMainWindow),
                                                 g_iDefaultWidth,
                                                 g_iDefaultHeight);
      gtk_window_set_keep_above (GTK_WINDOW (g_pMainWindow), g_iKeepOnTop);
      gtk_window_set_skip_pager_hint (GTK_WINDOW (g_pMainWindow),
                                                      !g_iAppearInPager);
      gtk_window_set_skip_taskbar_hint (GTK_WINDOW (g_pMainWindow),
                                                        !g_iAppearInTaskbar);
      if (g_iSticky)
            gtk_window_stick (GTK_WINDOW (g_pMainWindow));
      else
            gtk_window_unstick (GTK_WINDOW (g_pMainWindow));

      gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_pSpinButtonWidth),
                                             (gdouble) g_iDefaultWidth);
      gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_pSpinButtonHeight),
                                             (gdouble) g_iDefaultHeight);
      gtk_combo_box_set_active (GTK_COMBO_BOX (g_pComboBoxStartupSize),
                                            SIZE_CUSTOM);
      gtk_widget_set_sensitive (g_pTableStartupSize, TRUE);

      if (g_iDefaultX <= gdk_screen_width () &&
            g_iDefaultX >= 0 &&
            g_iDefaultY <= gdk_screen_height () &&
            g_iDefaultY >= 0)
            gtk_window_move (GTK_WINDOW (g_pMainWindow), g_iDefaultX, g_iDefaultY);

      hints.min_width = MIN_WIDTH;
      hints.min_height = MIN_HEIGHT;
      hints.max_width = MAX_WIDTH;
      hints.max_height = MAX_HEIGHT;

      gtk_window_set_geometry_hints (GTK_WINDOW (g_pMainWindow),
                                                   g_pMainWindow,
                                                   &hints,
                                                   GDK_HINT_MIN_SIZE |
                                                   GDK_HINT_MAX_SIZE);

      on_alpha_screen_changed (g_pMainWindow, NULL, NULL);

      /* that's needed here because a top-level GtkWindow does not listen to
       * "button-press-events" by default */
      gtk_widget_add_events (g_pMainWindow, GDK_BUTTON_PRESS_MASK);

      g_signal_connect (G_OBJECT (g_pMainWindow), "expose-event", G_CALLBACK (on_expose), NULL);
      g_signal_connect (G_OBJECT (g_pMainWindow), "configure-event", G_CALLBACK (on_configure), NULL);
      g_signal_connect (G_OBJECT (g_pMainWindow), "key-press-event", G_CALLBACK (on_key_press), NULL);
      g_signal_connect (G_OBJECT (g_pMainWindow), "button-press-event", G_CALLBACK (on_button_press), NULL);
      g_signal_connect (G_OBJECT (pSettingsMenuItem), "activate", G_CALLBACK (on_settings_activate), NULL);
      g_signal_connect (G_OBJECT (pInfoMenuItem), "activate", G_CALLBACK (on_info_activate), NULL);
      g_signal_connect (G_OBJECT (pQuitMenuItem), "activate", G_CALLBACK (on_quit_activate), NULL);
      g_signal_connect (G_OBJECT (g_pSettingsDialog), "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
      g_signal_connect (G_OBJECT (g_pInfoDialog), "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
      g_signal_connect (G_OBJECT (g_pComboBoxStartupSize), "changed", G_CALLBACK (on_startup_size_changed), g_pMainWindow);
      g_signal_connect (G_OBJECT (g_pSpinButtonWidth), "value-changed", G_CALLBACK (on_width_value_changed), g_pMainWindow);
      g_signal_connect (G_OBJECT (g_pSpinButtonHeight), "value-changed", G_CALLBACK (on_height_value_changed), g_pMainWindow);
      g_signal_connect (G_OBJECT (pComboBoxTheme), "changed", G_CALLBACK (on_theme_changed), (gpointer) g_pMainWindow);
      g_signal_connect (G_OBJECT (pCheckButtonSeconds), "toggled", G_CALLBACK (on_seconds_toggled), g_pMainWindow);
      g_signal_connect (G_OBJECT (pCheckButtonDate), "toggled", G_CALLBACK (on_date_toggled), g_pMainWindow);
      g_signal_connect (G_OBJECT (pCheckButtonKeepOnTop), "toggled", G_CALLBACK (on_keep_on_top_toggled), g_pMainWindow);
      g_signal_connect (G_OBJECT (pCheckButtonAppearInPager), "toggled", G_CALLBACK (on_appear_in_pager_toggled), g_pMainWindow);
      g_signal_connect (G_OBJECT (pCheckButtonAppearInTaskbar), "toggled", G_CALLBACK (on_appear_in_taskbar_toggled), g_pMainWindow);
      g_signal_connect (G_OBJECT (pCheckButtonSticky), "toggled", G_CALLBACK (on_sticky_toggled), g_pMainWindow);
      g_signal_connect (G_OBJECT (pCheckButton24h), "toggled", G_CALLBACK (on_24h_toggled), g_pMainWindow);
      g_signal_connect (G_OBJECT (pButtonHelp), "clicked", G_CALLBACK (on_help_clicked), NULL);
      g_signal_connect (G_OBJECT (pButtonClose), "clicked", G_CALLBACK (on_close_clicked), NULL);

      if (!GTK_WIDGET_VISIBLE (g_pMainWindow))
            gtk_widget_show_all (g_pMainWindow);

      if (g_iShowSeconds)
      {

            g_iuIntervalHandlerId = g_timeout_add (SECOND_INTERVAL,
                                                                     (GSourceFunc) time_handler,
                                                                     (gpointer) g_pMainWindow);
        
      }
      else
      {
            g_iuIntervalHandlerId = g_timeout_add (MINUTE_INTERVAL,
                                                                     (GSourceFunc) time_handler,
                                                                     (gpointer) g_pMainWindow);
      }

      g_pMainContext = gdk_cairo_create (g_pMainWindow->window);

      update_input_shape (g_pMainWindow, g_iDefaultWidth, g_iDefaultHeight);

      gtk_main ();

      for (iElement = 0; iElement < CLOCK_ELEMENTS; iElement++)
            rsvg_handle_free (g_pSvgHandles[iElement]);

      rsvg_term ();

      if (g_pThemeList)
            theme_list_delete (g_pThemeList);

      gtk_window_get_position (GTK_WINDOW (g_pMainWindow), &g_iDefaultX, &g_iDefaultY);
      gtk_window_get_size (GTK_WINDOW (g_pMainWindow),
                                     &g_iDefaultWidth,
                                     &g_iDefaultHeight);

      pcFilename = get_preferences_filename ();
      if (!write_settings (pcFilename,
                                     g_iDefaultX,
                                     g_iDefaultY,
                                     g_iDefaultWidth,
                                     g_iDefaultHeight,
                                     g_iShowSeconds,
                                     g_iShowDate,
                                     g_acTheme,
                                     g_iKeepOnTop,
                                     g_iAppearInPager,
                                     g_iAppearInTaskbar,
                                     g_iSticky,
                         g_i24))
      {
            printf ("Ups, there was an error while trying to save the preferences!\n");
      }

      if (pcFilename)
            free (pcFilename);

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index