Adding upstream version 0.3.5.2+svn20080509.
[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;
44 GtkTooltips *tip;
45 char *tfmt;
46 char *cfmt;
47 char *action;
48 short lastDay;
49 int bold;
50 int timer;
51 gboolean cal_show;
52} dclock;
53
54static void
55update_label_orient( Plugin* p );
56
57static GtkWidget *create_calendar()
58{
59 GtkWidget *win;
60 GtkWidget *calendar;
61
62 /* create a new window */
63 win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
64 gtk_window_set_default_size(GTK_WINDOW(win), 180, 180);
65 gtk_window_set_decorated(GTK_WINDOW(win), FALSE);
66 gtk_window_set_resizable (GTK_WINDOW(win), FALSE);
67 gtk_container_set_border_width(GTK_CONTAINER(win), 5);
68 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(win), TRUE);
69 gtk_window_set_skip_pager_hint(GTK_WINDOW(win), TRUE);
70// gtk_window_set_type_hint(GTK_WINDOW(win), GDK_WINDOW_TYPE_HINT_DOCK);
71 gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_MOUSE);
72 gtk_window_stick (GTK_WINDOW(win));
73
74 GtkVBox* box = gtk_vbox_new(FALSE, 0);
75
76 /* calendar */
77 calendar = gtk_calendar_new();
78 gtk_calendar_display_options(GTK_CALENDAR(calendar),
79 GTK_CALENDAR_SHOW_WEEK_NUMBERS |
80 GTK_CALENDAR_SHOW_DAY_NAMES |
81 GTK_CALENDAR_SHOW_HEADING);
82// gtk_container_add(GTK_CONTAINER(win), calendar);
83 gtk_box_pack_start_defaults( box, calendar );
84 gtk_container_add(GTK_CONTAINER(win), box);
85
86 gtk_widget_show_all(win);
87
88 RET(win);
89}
90
91static int
92actionProcess( void *arg )
93{
94 ENTER;
95 RET(system((char *) arg));
96}
97
98static gboolean
99clicked( GtkWidget *widget, GdkEventButton* evt, Plugin* plugin)
100{
101 dclock *dc = (dclock*)plugin->priv;
102 ENTER2;
103 if( evt->button == 3 ) /* right button */
104 {
105 GtkMenu* popup = lxpanel_get_panel_menu( plugin->panel, plugin, FALSE );
106 gtk_menu_popup( popup, NULL, NULL, NULL, NULL, evt->button, evt->time );
107 return TRUE;
108 }
109
110 if( dc->action ) {
111 pthread_t actionThread;
112 pthread_create(&actionThread, NULL, actionProcess, dc->action);
113 } else {
114 if (!dc->cal_show) {
115 dc->cal_show = TRUE;
116 dc->calwin = create_calendar();
117 } else {
118 dc->cal_show = FALSE;
119 gtk_widget_destroy(dc->calwin);
120 dc->calwin = NULL;
121 }
122 }
123 RET2(TRUE);
124}
125
126static gint
127clock_update(gpointer data )
128{
129 char output[64], str[64];
130 time_t now;
131 struct tm * detail;
132 dclock *dc;
133 gchar *utf8;
134
135 ENTER;
136 g_assert(data != NULL);
137 dc = (dclock *)data;
138
139 time(&now);
140 detail = localtime(&now);
141 strftime(output, sizeof(output),
142 (dc->cfmt ? dc->cfmt : DEFAULT_CLOCK_FORMAT), detail);
143
144 if (dc->bold&& dc->panel->usefontcolor)
145 g_snprintf(str, 64, "<span color=\"#%06x\"><b>%s</b></span>", gcolor2rgb24( &dc->panel->gfontcolor ), output);
146 else if (dc->bold)
147 g_snprintf(str, 64, "<b>%s</b>", output);
148 else if ( dc->panel->usefontcolor)
149 g_snprintf(str, 64, "<span color=\"#%06x\">%s</span>", gcolor2rgb24(&dc->panel->gfontcolor), output);
150 else
151 g_snprintf(str, 64, "%s", output);
152
153 gtk_label_set_markup (GTK_LABEL(dc->clockw), str);
154
155 if (detail->tm_mday != dc->lastDay) {
156 dc->lastDay = detail->tm_mday ;
157 strftime (output, sizeof(output),
158 (dc->tfmt ? dc->tfmt : DEFAULT_TIP_FORMAT), detail);
159 if ((utf8 = g_locale_to_utf8(output, -1, NULL, NULL, NULL))) {
160 gtk_tooltips_set_tip(dc->tip, dc->main, utf8, NULL);
161 g_free(utf8);
162 }
163 }
164
165 RET(TRUE);
166}
167
168
169static int
170dclock_constructor(Plugin *p, char** fp)
171{
172 line s;
173 dclock *dc;
174
175 ENTER;
176 dc = g_slice_new0(dclock);
177 g_return_val_if_fail(dc != NULL, 0);
178 p->priv = dc;
179
180 dc->panel = p->panel;
181
182 s.len = 256;
183 dc->cfmt = dc->tfmt = dc->action = dc->bold = 0;
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
223 dc->tip = p->panel->tooltips;
224
225 dc->tip = gtk_tooltips_new();
226#if GLIB_CHECK_VERSION( 2, 10, 0 )
227 g_object_ref_sink( dc->tip );
228#else
229 g_object_ref( dc->tip );
230 gtk_object_sink( dc->tip );
231#endif
232
233 dc->timer = g_timeout_add(1000, (GSourceFunc) clock_update, (gpointer)dc);
234
235 clock_update( dc );
236
237 /* store the created Plugin widget in Plugin->pwid */
238 p->pwid = dc->main;
239
240 RET(1);
241
242 error:
243 g_free(dc->cfmt);
244 g_free(dc->tfmt);
245 g_free(dc->action);
246 g_slice_free(dclock, dc);
247 RET(0);
248}
249
250
251static void
252dclock_destructor(Plugin *p)
253{
254 dclock *dc = (dclock *)p->priv;
255
256 ENTER;
257 dc = (dclock *) p->priv;
258 if (dc->timer)
259 g_source_remove(dc->timer);
260
261 /* g_object_unref( dc->tip ); */
262 g_free(dc->cfmt);
263 g_free(dc->tfmt);
264 g_free(dc->action);
265 g_slice_free(dclock, dc);
266 RET();
267}
268
269static void apply_config( Plugin* p )
270{
271 /* NOTE: This dirty hack is used to force the update of tooltip
272 because tooltip will be updated when dc->lastDay != today.
273 */
274 dclock* dc = (dclock*)p->priv;
275 --dc->lastDay;
276 clock_update( dc );
277}
278
279static void dclock_config( Plugin *p, GtkWindow* parent )
280{
281 GtkWidget* dlg;
282 dclock *dc = (dclock *)p->priv;
283 dlg = create_generic_config_dlg( _(p->class->name),
284 GTK_WIDGET(parent),
285 (GSourceFunc) apply_config, (gpointer) p,
286 _("Clock Format"), &dc->cfmt, G_TYPE_STRING,
287 _("Tooltip Format"), &dc->tfmt, G_TYPE_STRING,
288 _("Action"), &dc->action, G_TYPE_STRING,
289 _("Bold font"), &dc->bold, G_TYPE_BOOLEAN,
290 NULL );
291 gtk_window_present( GTK_WINDOW(dlg) );
292}
293
294static void save_config( Plugin* p, FILE* fp )
295{
296 dclock *dc = (dclock *)p->priv;
297 lxpanel_put_str( fp, "ClockFmt", dc->cfmt );
298 lxpanel_put_str( fp, "TooltipFmt", dc->tfmt );
299 lxpanel_put_str( fp, "Action", dc->action );
300 lxpanel_put_int( fp, "BoldFont", dc->bold );
301}
302
303static void
304update_label_orient( Plugin* p )
305{
306 dclock *dc = (dclock *)p->priv;
307 GtkLabel* label = GTK_LABEL(dc->clockw);
308 /* FIXME: gtk+ has only limited support for this, sigh! */
309 gdouble angle;
310 if( p->panel->edge == EDGE_LEFT )
311 angle = 90.0;
312 else if( p->panel->edge == EDGE_RIGHT )
313 angle = 270.0;
314 else
315 angle = 0.0;
316 gtk_label_set_angle( GTK_LABEL(label), angle );
317}
318
319PluginClass dclock_plugin_class = {
320 fname: NULL,
321 count: 0,
322
323 type : "dclock",
324 name : N_("Digital Clock"),
325 version: "1.0",
326 description : N_("Display Digital clock and Tooltip"),
327
328 constructor : dclock_constructor,
329 destructor : dclock_destructor,
330 config : dclock_config,
331 save : save_config,
332 orientation : update_label_orient
333};