Adding upstream version 0.3.8.1.
[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;
6cc5e1a6
DB
224#if GLIB_CHECK_VERSION( 2, 10, 0 )
225 g_object_ref_sink( dc->tip );
226#else
227 g_object_ref( dc->tip );
228 gtk_object_sink( dc->tip );
229#endif
230
231 dc->timer = g_timeout_add(1000, (GSourceFunc) clock_update, (gpointer)dc);
232
233 clock_update( dc );
234
235 /* store the created Plugin widget in Plugin->pwid */
236 p->pwid = dc->main;
237
238 RET(1);
239
240 error:
241 g_free(dc->cfmt);
242 g_free(dc->tfmt);
243 g_free(dc->action);
244 g_slice_free(dclock, dc);
245 RET(0);
246}
247
248
249static void
250dclock_destructor(Plugin *p)
251{
252 dclock *dc = (dclock *)p->priv;
253
254 ENTER;
6cc5e1a6
DB
255 if (dc->timer)
256 g_source_remove(dc->timer);
257
258 /* g_object_unref( dc->tip ); */
3f7f0eb5
DB
259 gtk_widget_destroy(dc->clockw);
260 gtk_widget_destroy(dc->main);
6cc5e1a6
DB
261 g_free(dc->cfmt);
262 g_free(dc->tfmt);
263 g_free(dc->action);
264 g_slice_free(dclock, dc);
265 RET();
266}
267
268static void apply_config( Plugin* p )
269{
270 /* NOTE: This dirty hack is used to force the update of tooltip
271 because tooltip will be updated when dc->lastDay != today.
272 */
273 dclock* dc = (dclock*)p->priv;
274 --dc->lastDay;
275 clock_update( dc );
276}
277
278static void dclock_config( Plugin *p, GtkWindow* parent )
279{
280 GtkWidget* dlg;
281 dclock *dc = (dclock *)p->priv;
282 dlg = create_generic_config_dlg( _(p->class->name),
283 GTK_WIDGET(parent),
284 (GSourceFunc) apply_config, (gpointer) p,
285 _("Clock Format"), &dc->cfmt, G_TYPE_STRING,
286 _("Tooltip Format"), &dc->tfmt, G_TYPE_STRING,
287 _("Action"), &dc->action, G_TYPE_STRING,
288 _("Bold font"), &dc->bold, G_TYPE_BOOLEAN,
289 NULL );
290 gtk_window_present( GTK_WINDOW(dlg) );
291}
292
293static void save_config( Plugin* p, FILE* fp )
294{
295 dclock *dc = (dclock *)p->priv;
296 lxpanel_put_str( fp, "ClockFmt", dc->cfmt );
297 lxpanel_put_str( fp, "TooltipFmt", dc->tfmt );
298 lxpanel_put_str( fp, "Action", dc->action );
299 lxpanel_put_int( fp, "BoldFont", dc->bold );
300}
301
302static void
303update_label_orient( Plugin* p )
304{
305 dclock *dc = (dclock *)p->priv;
306 GtkLabel* label = GTK_LABEL(dc->clockw);
307 /* FIXME: gtk+ has only limited support for this, sigh! */
308 gdouble angle;
309 if( p->panel->edge == EDGE_LEFT )
310 angle = 90.0;
311 else if( p->panel->edge == EDGE_RIGHT )
312 angle = 270.0;
313 else
314 angle = 0.0;
315 gtk_label_set_angle( GTK_LABEL(label), angle );
316}
317
318PluginClass dclock_plugin_class = {
319 fname: NULL,
320 count: 0,
321
322 type : "dclock",
323 name : N_("Digital Clock"),
324 version: "1.0",
325 description : N_("Display Digital clock and Tooltip"),
326
327 constructor : dclock_constructor,
328 destructor : dclock_destructor,
329 config : dclock_config,
330 save : save_config,
331 orientation : update_label_orient
332};