Adding upstream version 0.4.1+svn20090524.
[debian/lxpanel.git] / src / plugins / dclock.c
CommitLineData
6cc5e1a6
DB
1/**
2 * Copyright (c) 2006 LxDE Developers, see the file AUTHORS for details.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#include <time.h>
20#include <sys/time.h>
21#include <sys/types.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <glib/gi18n.h>
26#include <pthread.h>
27
28#include "panel.h"
29#include "misc.h"
30#include "plugin.h"
31#include "glib-mem.h"
32
33#include "dbg.h"
34
35#define DEFAULT_TIP_FORMAT "%A %x"
36#define DEFAULT_CLOCK_FORMAT "%R"
37
38typedef struct {
39 Panel* panel;
40 GtkWidget *eb;
41 GtkWidget *main;
42 GtkWidget *clockw;
43 GtkWidget *calwin;
6cc5e1a6
DB
44 char *tfmt;
45 char *cfmt;
46 char *action;
47 short lastDay;
48 int bold;
49 int timer;
50 gboolean cal_show;
51} dclock;
52
53static void
54update_label_orient( Plugin* p );
55
56static GtkWidget *create_calendar()
57{
58 GtkWidget *win;
59 GtkWidget *calendar;
60
61 /* create a new window */
62 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
63 gtk_window_set_default_size(GTK_WINDOW(win), 180, 180);
64 gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
65 gtk_window_set_resizable (GTK_WINDOW(win), FALSE);
66 gtk_container_set_border_width(GTK_CONTAINER(win), 5);
67 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(win), TRUE);
68 gtk_window_set_skip_pager_hint(GTK_WINDOW(win), TRUE);
69// gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);
70 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_MOUSE);
71 gtk_window_stick (GTK_WINDOW(win));
72
7486d297 73 GtkVBox* box = (GtkVBox*)gtk_vbox_new(FALSE, 0);
6cc5e1a6
DB
74
75 /* calendar */
76 calendar = gtk_calendar_new();
77 gtk_calendar_display_options(GTK_CALENDAR(calendar),
78 GTK_CALENDAR_SHOW_WEEK_NUMBERS |
79 GTK_CALENDAR_SHOW_DAY_NAMES |
80 GTK_CALENDAR_SHOW_HEADING);
81// gtk_container_add(GTK_CONTAINER(win), calendar);
7486d297
DB
82 gtk_box_pack_start_defaults( GTK_BOX(box), calendar );
83 gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(box));
6cc5e1a6
DB
84
85 gtk_widget_show_all(win);
86
87 RET(win);
88}
89
7486d297 90static void *
6cc5e1a6
DB
91actionProcess( void *arg )
92{
93 ENTER;
7486d297 94 RET((void *)system((char *) arg));
6cc5e1a6
DB
95}
96
97static gboolean
98clicked( GtkWidget *widget, GdkEventButton* evt, Plugin* plugin)
99{
100 dclock *dc = (dclock*)plugin->priv;
101 ENTER2;
102 if( evt->button == 3 ) /* right button */
103 {
104 GtkMenu* popup = lxpanel_get_panel_menu( plugin->panel, plugin, FALSE );
105 gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
106 return TRUE;
107 }
108
109 if( dc->action ) {
110 pthread_t actionThread;
111 pthread_create(&actionThread, NULL, actionProcess, dc->action);
112 } else {
113 if (!dc->cal_show) {
114 dc->cal_show = TRUE;
115 dc->calwin = create_calendar();
116 } else {
117 dc->cal_show = FALSE;
118 gtk_widget_destroy(dc->calwin);
119 dc->calwin = NULL;
120 }
121 }
7486d297 122 RET2(FALSE);
6cc5e1a6
DB
123}
124
125static gint
126clock_update(gpointer data )
127{
128 char output[64], str[64];
129 time_t now;
130 struct tm * detail;
131 dclock *dc;
132 gchar *utf8;
133
134 ENTER;
135 g_assert(data != NULL);
136 dc = (dclock *)data;
137
138 time(&now);
139 detail = localtime(&now);
140 strftime(output, sizeof(output),
141 (dc->cfmt ? dc->cfmt : DEFAULT_CLOCK_FORMAT), detail);
142
143 if (dc->bold&& dc->panel->usefontcolor)
144 g_snprintf(str, 64, "<span color=\"#%06x\"><b>%s</b></span>", gcolor2rgb24( &dc->panel->gfontcolor ), output);
145 else if (dc->bold)
146 g_snprintf(str, 64, "<b>%s</b>", output);
147 else if ( dc->panel->usefontcolor)
148 g_snprintf(str, 64, "<span color=\"#%06x\">%s</span>", gcolor2rgb24(&dc->panel->gfontcolor), output);
149 else
150 g_snprintf(str, 64, "%s", output);
151
152 gtk_label_set_markup (GTK_LABEL(dc->clockw), str);
153
154 if (detail->tm_mday != dc->lastDay) {
155 dc->lastDay = detail->tm_mday ;
156 strftime (output, sizeof(output),
157 (dc->tfmt ? dc->tfmt : DEFAULT_TIP_FORMAT), detail);
158 if ((utf8 = g_locale_to_utf8(output, -1, NULL, NULL, NULL))) {
7486d297 159 gtk_widget_set_tooltip_text(dc->main, utf8);
6cc5e1a6
DB
160 g_free(utf8);
161 }
162 }
163
164 RET(TRUE);
165}
166
167
168static int
169dclock_constructor(Plugin *p, char** fp)
170{
171 line s;
172 dclock *dc;
173
174 ENTER;
175 dc = g_slice_new0(dclock);
176 g_return_val_if_fail(dc != NULL, 0);
177 p->priv = dc;
178
179 dc->panel = p->panel;
180
181 s.len = 256;
7486d297
DB
182 dc->cfmt = dc->tfmt = dc->action = NULL;
183 dc->bold = 0;
6cc5e1a6
DB
184 dc->bold = TRUE;
185 dc->cal_show = FALSE;
186 if( fp )
187 {
188 while (lxpanel_get_line(fp, &s) != LINE_BLOCK_END) {
189 if (s.type == LINE_NONE) {
190 ERR( "dclock: illegal token %s\n", s.str);
191 goto error;
192 }
193 if (s.type == LINE_VAR) {
194 if (!g_ascii_strcasecmp(s.t[0], "ClockFmt"))
195 dc->cfmt = g_strdup(s.t[1]);
196 else if (!g_ascii_strcasecmp(s.t[0], "TooltipFmt"))
197 dc->tfmt = g_strdup(s.t[1]);
198 else if (!g_ascii_strcasecmp(s.t[0], "Action"))
199 dc->action = g_strdup(s.t[1]);
200 else if (!g_ascii_strcasecmp(s.t[0], "BoldFont"))
201 dc->bold = str2num(bool_pair, s.t[1], 0);
202 else {
203 ERR( "dclock: unknown var %s\n", s.t[0]);
204 goto error;
205 }
206 } else {
207 ERR( "dclock: illegal in this context %s\n", s.str);
208 goto error;
209 }
210 }
211 }
212 dc->main = gtk_event_box_new();
213
214 g_signal_connect (G_OBJECT (dc->main), "button_press_event",
215 G_CALLBACK (clicked), (gpointer) p);
216 dc->clockw = gtk_label_new("");
217 gtk_misc_set_alignment(GTK_MISC(dc->clockw), 0.5, 0.5);
218 gtk_misc_set_padding(GTK_MISC(dc->clockw), 4, 0);
219 update_label_orient( p );
220 gtk_container_add(GTK_CONTAINER(dc->main), dc->clockw);
221 gtk_widget_show_all(dc->main);
222
6cc5e1a6
DB
223 dc->timer = g_timeout_add(1000, (GSourceFunc) clock_update, (gpointer)dc);
224
225 clock_update( dc );
226
227 /* store the created Plugin widget in Plugin->pwid */
228 p->pwid = dc->main;
229
230 RET(1);
231
232 error:
233 g_free(dc->cfmt);
234 g_free(dc->tfmt);
235 g_free(dc->action);
236 g_slice_free(dclock, dc);
237 RET(0);
238}
239
240
241static void
242dclock_destructor(Plugin *p)
243{
244 dclock *dc = (dclock *)p->priv;
245
246 ENTER;
6cc5e1a6
DB
247 if (dc->timer)
248 g_source_remove(dc->timer);
249
250 /* g_object_unref( dc->tip ); */
7486d297
DB
251 gtk_widget_destroy(dc->clockw);
252
253 /* p->pwid = dc->main;
254 gtk_widget_destroy(dc->main); */
6cc5e1a6
DB
255 g_free(dc->cfmt);
256 g_free(dc->tfmt);
257 g_free(dc->action);
258 g_slice_free(dclock, dc);
259 RET();
260}
261
262static void apply_config( Plugin* p )
263{
264 /* NOTE: This dirty hack is used to force the update of tooltip
265 because tooltip will be updated when dc->lastDay != today.
266 */
267 dclock* dc = (dclock*)p->priv;
268 --dc->lastDay;
269 clock_update( dc );
270}
271
272static void dclock_config( Plugin *p, GtkWindow* parent )
273{
274 GtkWidget* dlg;
275 dclock *dc = (dclock *)p->priv;
276 dlg = create_generic_config_dlg( _(p->class->name),
277 GTK_WIDGET(parent),
278 (GSourceFunc) apply_config, (gpointer) p,
7486d297
DB
279 _("Clock Format"), &dc->cfmt, CONF_TYPE_STR,
280 _("Tooltip Format"), &dc->tfmt, CONF_TYPE_STR,
281 _("Action"), &dc->action, CONF_TYPE_STR,
282 _("Bold font"), &dc->bold, CONF_TYPE_BOOL,
6cc5e1a6
DB
283 NULL );
284 gtk_window_present( GTK_WINDOW(dlg) );
285}
286
287static void save_config( Plugin* p, FILE* fp )
288{
289 dclock *dc = (dclock *)p->priv;
290 lxpanel_put_str( fp, "ClockFmt", dc->cfmt );
291 lxpanel_put_str( fp, "TooltipFmt", dc->tfmt );
292 lxpanel_put_str( fp, "Action", dc->action );
293 lxpanel_put_int( fp, "BoldFont", dc->bold );
294}
295
296static void
297update_label_orient( Plugin* p )
298{
299 dclock *dc = (dclock *)p->priv;
300 GtkLabel* label = GTK_LABEL(dc->clockw);
301 /* FIXME: gtk+ has only limited support for this, sigh! */
302 gdouble angle;
303 if( p->panel->edge == EDGE_LEFT )
304 angle = 90.0;
305 else if( p->panel->edge == EDGE_RIGHT )
306 angle = 270.0;
307 else
308 angle = 0.0;
309 gtk_label_set_angle( GTK_LABEL(label), angle );
310}
311
312PluginClass dclock_plugin_class = {
313 fname: NULL,
314 count: 0,
315
316 type : "dclock",
317 name : N_("Digital Clock"),
318 version: "1.0",
319 description : N_("Display Digital clock and Tooltip"),
320
321 constructor : dclock_constructor,
322 destructor : dclock_destructor,
323 config : dclock_config,
324 save : save_config,
325 orientation : update_label_orient
326};