1 /* Sticky Notes
2 * Copyright (C) 2002-2003 Loban A Rahman
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, or (at your option)
7 * 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
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 #include <config.h>
21 #include <libxml/parser.h>
22 #include <X11/Xatom.h>
23 #include <gdk/gdkx.h>
24 #include <gtk/gtk.h>
25 #define WNCK_I_KNOW_THIS_IS_UNSTABLE 1
26 #include <libwnck/libwnck.h>
27 #include <string.h>
28 #include <sys/stat.h>
29
30 #include <gtksourceview/gtksource.h>
31
32 #include "stickynotes.h"
33 #include "stickynotes_callbacks.h"
34 #include "util.h"
35 #include "stickynotes_applet.h"
36
37 /* Stop gcc complaining about xmlChar's signedness */
38 #define XML_CHAR(str) ((xmlChar *) (str))
39 #define STICKYNOTES_ICON_SIZE 8
40
41 static gboolean save_scheduled = FALSE;
42
43 static void response_cb (GtkWidget *dialog, gint id, gpointer data);
44
45 /* Based on a function found in wnck */
46 static void
set_icon_geometry(GdkWindow * window,int x,int y,int width,int height)47 set_icon_geometry (GdkWindow *window,
48 int x,
49 int y,
50 int width,
51 int height)
52 {
53 gulong data[4];
54 Display *dpy;
55
56 dpy = gdk_x11_display_get_xdisplay (gdk_window_get_display (window));
57
58 data[0] = x;
59 data[1] = y;
60 data[2] = width;
61 data[3] = height;
62
63 XChangeProperty (dpy,
64 GDK_WINDOW_XID (window),
65 gdk_x11_get_xatom_by_name_for_display (gdk_window_get_display (window),
66 "_NET_WM_ICON_GEOMETRY"),
67 XA_CARDINAL, 32, PropModeReplace,
68 (guchar *)&data, 4);
69 }
70
71 /* Called when a timeout occurs. */
72 static gboolean
timeout_happened(gpointer data)73 timeout_happened (gpointer data)
74 {
75 if (GPOINTER_TO_UINT (data) == stickynotes->last_timeout_data)
76 stickynotes_save ();
77
78 return FALSE;
79 }
80
81 /* Called when a text buffer is changed. */
82 static void
buffer_changed(GtkTextBuffer * buffer,StickyNote * note)83 buffer_changed (GtkTextBuffer *buffer,
84 StickyNote *note)
85 {
86 if ( (note->h + note->y) > stickynotes->max_height )
87 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (note->w_scroller),
88 GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
89
90 /* When a buffer is changed, we set a 10 second timer. When
91 the timer triggers, we will save the buffer if there have
92 been no subsequent changes. */
93 ++stickynotes->last_timeout_data;
94 g_timeout_add_seconds (10, (GSourceFunc) timeout_happened,
95 GUINT_TO_POINTER (stickynotes->last_timeout_data));
96 }
97
98 /* Create a new (empty) Sticky Note at a specific position
99 and with specific size */
100 static StickyNote *
stickynote_new_aux(GdkScreen * screen,gint x,gint y,gint w,gint h)101 stickynote_new_aux (GdkScreen *screen,
102 gint x,
103 gint y,
104 gint w,
105 gint h)
106 {
107 StickyNote *note;
108 GtkBuilder *builder;
109
110 note = g_new (StickyNote, 1);
111
112 builder = gtk_builder_new ();
113 gtk_builder_add_from_resource (builder,
114 GRESOURCE "sticky-notes-note.ui",
115 NULL);
116 gtk_builder_add_from_resource (builder,
117 GRESOURCE "sticky-notes-properties.ui",
118 NULL);
119
120 note->w_window = GTK_WIDGET (gtk_builder_get_object (builder,
121 "stickynote_window"));
122 gtk_window_set_screen (GTK_WINDOW (note->w_window),screen);
123 gtk_window_set_decorated (GTK_WINDOW (note->w_window), FALSE);
124 gtk_window_set_skip_taskbar_hint (GTK_WINDOW (note->w_window), TRUE);
125 gtk_window_set_skip_pager_hint (GTK_WINDOW (note->w_window), TRUE);
126 gtk_widget_add_events (note->w_window, GDK_BUTTON_PRESS_MASK);
127
128 note->w_title = GTK_WIDGET (gtk_builder_get_object (builder,
129 "title_label"));
130 note->w_body = GTK_WIDGET (gtk_builder_get_object (builder,
131 "body_text"));
132 note->w_scroller = GTK_WIDGET (gtk_builder_get_object (builder,
133 "body_scroller"));
134 note->w_lock = GTK_WIDGET (gtk_builder_get_object (builder,
135 "lock_button"));
136 gtk_widget_add_events (note->w_lock, GDK_BUTTON_PRESS_MASK);
137
138 note->buffer =
139 GTK_SOURCE_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (note->w_body)));
140
141 note->w_close =
142 GTK_WIDGET (gtk_builder_get_object (builder, "close_button"));
143 gtk_widget_add_events (note->w_close, GDK_BUTTON_PRESS_MASK);
144 note->w_resize_se =
145 GTK_WIDGET (gtk_builder_get_object (builder, "resize_se_box"));
146 gtk_widget_add_events (note->w_resize_se, GDK_BUTTON_PRESS_MASK);
147 note->w_resize_sw =
148 GTK_WIDGET (gtk_builder_get_object (builder, "resize_sw_box"));
149 gtk_widget_add_events (note->w_resize_sw, GDK_BUTTON_PRESS_MASK);
150
151 note->img_lock =
152 GTK_IMAGE (gtk_builder_get_object (builder, "lock_img"));
153 note->img_close =
154 GTK_IMAGE (gtk_builder_get_object (builder, "close_img"));
155 note->img_resize_se =
156 GTK_IMAGE (gtk_builder_get_object (builder, "resize_se_img"));
157 note->img_resize_sw =
158 GTK_IMAGE (gtk_builder_get_object (builder, "resize_sw_img"));
159
160 /* deal with RTL environments */
161 gtk_widget_set_direction (GTK_WIDGET (gtk_builder_get_object (builder, "resize_bar")),
162 GTK_TEXT_DIR_LTR);
163
164 note->w_menu = GTK_WIDGET (gtk_builder_get_object (builder,
165 "stickynote_menu"));
166 note->ta_lock_toggle_item =
167 GTK_TOGGLE_ACTION (gtk_builder_get_object (builder,
168 "popup_toggle_lock"));
169
170 note->w_properties =
171 GTK_WIDGET (gtk_builder_get_object (builder,
172 "stickynote_properties"));
173 gtk_window_set_screen (GTK_WINDOW (note->w_properties), screen);
174
175 note->w_entry =
176 GTK_WIDGET (gtk_builder_get_object (builder, "title_entry"));
177 note->w_color =
178 GTK_WIDGET (gtk_builder_get_object (builder, "note_color"));
179 note->w_color_label =
180 GTK_WIDGET (gtk_builder_get_object (builder, "color_label"));
181 note->w_font_color =
182 GTK_WIDGET (gtk_builder_get_object (builder, "font_color"));
183 note->w_font_color_label =
184 GTK_WIDGET (gtk_builder_get_object (builder,
185 "font_color_label"));
186 note->w_font =
187 GTK_WIDGET (gtk_builder_get_object (builder, "note_font"));
188 note->w_font_label =
189 GTK_WIDGET (gtk_builder_get_object (builder, "font_label"));
190 note->w_def_color =
191 GTK_WIDGET (>K_CHECK_BUTTON (gtk_builder_get_object (builder,
192 "def_color_check"))->toggle_button);
193 note->w_def_font =
194 GTK_WIDGET (>K_CHECK_BUTTON (gtk_builder_get_object (builder,
195 "def_font_check"))->toggle_button);
196
197 note->color = NULL;
198 note->font_color = NULL;
199 note->font = NULL;
200 note->locked = FALSE;
201 note->x = x;
202 note->y = y;
203 note->w = w;
204 note->h = h;
205
206 /* Customize the window */
207 if (g_settings_get_boolean (stickynotes->settings, "sticky"))
208 gtk_window_stick (GTK_WINDOW (note->w_window));
209
210 if (w == 0 || h == 0)
211 gtk_window_resize (GTK_WINDOW (note->w_window),
212 g_settings_get_int (stickynotes->settings,
213 "default-width"),
214 g_settings_get_int (stickynotes->settings,
215 "default-height"));
216 else
217 gtk_window_resize (GTK_WINDOW (note->w_window),
218 note->w,
219 note->h);
220
221 if (x != -1 && y != -1)
222 gtk_window_move (GTK_WINDOW (note->w_window),
223 note->x,
224 note->y);
225
226 /* Set the button images */
227 gtk_image_set_from_icon_name (note->img_close,
228 STICKYNOTES_STOCK_CLOSE,
229 GTK_ICON_SIZE_MENU);
230 gtk_image_set_pixel_size (note->img_close,
231 STICKYNOTES_ICON_SIZE);
232
233 gtk_image_set_from_icon_name (note->img_resize_se,
234 STICKYNOTES_STOCK_RESIZE_SE,
235 GTK_ICON_SIZE_MENU);
236 gtk_image_set_pixel_size (note->img_resize_se,
237 STICKYNOTES_ICON_SIZE);
238
239 gtk_image_set_from_icon_name (note->img_resize_sw,
240 STICKYNOTES_STOCK_RESIZE_SW,
241 GTK_ICON_SIZE_MENU);
242 gtk_image_set_pixel_size (note->img_resize_sw,
243 STICKYNOTES_ICON_SIZE);
244
245 gtk_widget_show (note->w_lock);
246 gtk_widget_show (note->w_close);
247 gtk_widget_show (GTK_WIDGET (gtk_builder_get_object (builder,
248 "resize_bar")));
249
250 /* Customize the title and colors, hide and unlock */
251 stickynote_set_title (note, NULL);
252 stickynote_set_color (note, NULL, NULL, TRUE);
253 stickynote_set_font (note, NULL, TRUE);
254 stickynote_set_locked (note, FALSE);
255
256 gtk_widget_realize (note->w_window);
257
258 /* Connect a popup menu to all buttons and title */
259 /* GtkBuilder holds and drops the references to all the widgets it
260 * creates for as long as it exist (GtkBuilder). Hence in our callback
261 * we would have an invalid GtkMenu. We need to ref it.
262 */
263 g_object_ref (note->w_menu);
264
265 g_signal_connect (note->w_window, "button-press-event",
266 G_CALLBACK (stickynote_show_popup_menu),
267 note->w_menu);
268
269 g_signal_connect (note->w_lock, "button-press-event",
270 G_CALLBACK (stickynote_show_popup_menu),
271 note->w_menu);
272
273 g_signal_connect (note->w_close, "button-press-event",
274 G_CALLBACK (stickynote_show_popup_menu),
275 note->w_menu);
276
277 g_signal_connect (note->w_resize_se, "button-press-event",
278 G_CALLBACK (stickynote_show_popup_menu),
279 note->w_menu);
280
281 g_signal_connect (note->w_resize_sw, "button-press-event",
282 G_CALLBACK (stickynote_show_popup_menu),
283 note->w_menu);
284
285 /* Connect a properties dialog to the note */
286 gtk_window_set_transient_for (GTK_WINDOW (note->w_properties),
287 GTK_WINDOW (note->w_window));
288 gtk_dialog_set_default_response (GTK_DIALOG (note->w_properties),
289 GTK_RESPONSE_CLOSE);
290 g_signal_connect (note->w_properties, "response",
291 G_CALLBACK (response_cb),
292 note);
293
294 /* Connect signals to the sticky note */
295 g_signal_connect (note->w_lock, "clicked",
296 G_CALLBACK (stickynote_toggle_lock_cb),
297 note);
298
299 g_signal_connect (note->w_close, "clicked",
300 G_CALLBACK (stickynote_close_cb),
301 note);
302
303 g_signal_connect (note->w_resize_se, "button-press-event",
304 G_CALLBACK (stickynote_resize_cb),
305 note);
306
307 g_signal_connect (note->w_resize_sw, "button-press-event",
308 G_CALLBACK (stickynote_resize_cb),
309 note);
310
311 g_signal_connect (note->w_window, "button-press-event",
312 G_CALLBACK (stickynote_move_cb),
313 note);
314
315 g_signal_connect (note->w_window, "configure-event",
316 G_CALLBACK (stickynote_configure_cb),
317 note);
318
319 g_signal_connect (note->w_window, "delete-event",
320 G_CALLBACK (stickynote_delete_cb),
321 note);
322
323 g_signal_connect (gtk_builder_get_object (builder, "popup_create"), "activate",
324 G_CALLBACK (popup_create_cb),
325 note);
326
327 g_signal_connect (gtk_builder_get_object (builder, "popup_destroy"), "activate",
328 G_CALLBACK (popup_destroy_cb),
329 note);
330
331 g_signal_connect (gtk_builder_get_object (builder, "popup_toggle_lock"), "toggled",
332 G_CALLBACK (popup_toggle_lock_cb),
333 note);
334
335 g_signal_connect (gtk_builder_get_object (builder, "popup_properties"), "activate",
336 G_CALLBACK (popup_properties_cb),
337 note);
338
339 g_signal_connect_swapped (note->w_entry, "changed",
340 G_CALLBACK (properties_apply_title_cb),
341 note);
342
343 g_signal_connect (note->w_color, "color-set",
344 G_CALLBACK (properties_color_cb),
345 note);
346
347 g_signal_connect (note->w_font_color, "color-set",
348 G_CALLBACK (properties_color_cb),
349 note);
350
351 g_signal_connect_swapped (note->w_def_color, "toggled",
352 G_CALLBACK (properties_apply_color_cb),
353 note);
354
355 g_signal_connect (note->w_font, "font-set",
356 G_CALLBACK (properties_font_cb),
357 note);
358
359 g_signal_connect_swapped (note->w_def_font, "toggled",
360 G_CALLBACK (properties_apply_font_cb),
361 note);
362
363 g_signal_connect (note->w_entry, "activate",
364 G_CALLBACK (properties_activate_cb),
365 note);
366
367 g_signal_connect (note->w_properties, "delete-event",
368 G_CALLBACK (gtk_widget_hide),
369 note);
370
371 g_object_unref (builder);
372
373 g_signal_connect_after (note->w_body, "button-press-event",
374 G_CALLBACK (gtk_true),
375 note);
376
377 g_signal_connect (gtk_text_view_get_buffer (GTK_TEXT_VIEW (note->w_body)), "changed",
378 G_CALLBACK (buffer_changed),
379 note);
380
381 return note;
382 }
383
384 /* Create a new (empty) Sticky Note */
385 StickyNote *
stickynote_new(GdkScreen * screen)386 stickynote_new (GdkScreen *screen)
387 {
388 return stickynote_new_aux (screen, -1, -1, 0, 0);
389 }
390
391 /* Destroy a Sticky Note */
stickynote_free(StickyNote * note)392 void stickynote_free (StickyNote *note)
393 {
394 gtk_widget_destroy (note->w_properties);
395 gtk_widget_destroy (note->w_menu);
396 gtk_widget_destroy (note->w_window);
397
398 g_free (note->color);
399 g_free (note->font_color);
400 g_free (note->font);
401
402 g_free (note);
403 }
404
405 /* Change the sticky note title and color */
stickynote_change_properties(StickyNote * note)406 void stickynote_change_properties (StickyNote *note)
407 {
408 char *color_str = NULL;
409
410 gtk_entry_set_text (GTK_ENTRY (note->w_entry),
411 gtk_label_get_text (GTK_LABEL (note->w_title)));
412
413 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (note->w_def_color),
414 note->color == NULL);
415
416 if (note->color)
417 color_str = g_strdup (note->color);
418 else {
419 color_str = g_settings_get_string (stickynotes->settings,
420 "default-color");
421 }
422
423 if (color_str) {
424 GdkRGBA color;
425 gdk_rgba_parse (&color, color_str);
426 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (note->w_color),
427 &color);
428 g_free (color_str);
429 }
430
431 if (note->font_color)
432 color_str = g_strdup (note->font_color);
433 else {
434 color_str = g_settings_get_string (stickynotes->settings,
435 "default-font-color");
436 }
437
438 if (color_str) {
439 GdkRGBA font_color;
440 gdk_rgba_parse (&font_color, color_str);
441 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (note->w_font_color),
442 &font_color);
443 g_free (color_str);
444 }
445
446 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (note->w_def_font),
447 note->font == NULL);
448 if (note->font)
449 gtk_font_button_set_font_name (GTK_FONT_BUTTON (note->w_font),
450 note->font);
451
452 gtk_widget_show (note->w_properties);
453
454 stickynotes_save ();
455 }
456
457 static void
response_cb(GtkWidget * dialog,gint id,gpointer data)458 response_cb (GtkWidget *dialog,
459 gint id, gpointer data)
460 {
461 if (id == GTK_RESPONSE_HELP)
462 gtk_show_uri_on_window (GTK_WINDOW (dialog),
463 "help:mate-stickynotes-applet/stickynotes-settings-individual",
464 gtk_get_current_event_time (),
465 NULL);
466 else if (id == GTK_RESPONSE_CLOSE)
467 gtk_widget_hide (dialog);
468 }
469
470 /* Check if a sticky note is empty */
471 gboolean
stickynote_get_empty(const StickyNote * note)472 stickynote_get_empty (const StickyNote *note)
473 {
474 return gtk_text_buffer_get_char_count (gtk_text_view_get_buffer (GTK_TEXT_VIEW (note->w_body))) == 0;
475 }
476
477 /* Set the sticky note title */
478 void
stickynote_set_title(StickyNote * note,const gchar * title)479 stickynote_set_title (StickyNote *note,
480 const gchar *title)
481 {
482 /* If title is NULL, use the current date as the title. */
483 if (!title) {
484 GDateTime *now;
485 gchar *date_title;
486 gchar *date_format;
487
488 date_format = g_settings_get_string (stickynotes->settings, "date-format");
489 if (!date_format)
490 date_format = g_strdup ("%x");
491
492 now = g_date_time_new_now_local ();
493 date_title = g_date_time_format (now, date_format);
494
495 gtk_window_set_title (GTK_WINDOW (note->w_window), date_title);
496 gtk_label_set_text (GTK_LABEL (note->w_title), date_title);
497
498 g_date_time_unref (now);
499 g_free (date_title);
500 g_free (date_format);
501 }
502 else {
503 gtk_window_set_title (GTK_WINDOW (note->w_window), title);
504 gtk_label_set_text (GTK_LABEL (note->w_title), title);
505 }
506 }
507
508 /* Set the sticky note color */
509 void
stickynote_set_color(StickyNote * note,const gchar * color_str,const gchar * font_color_str,gboolean save)510 stickynote_set_color (StickyNote *note,
511 const gchar *color_str,
512 const gchar *font_color_str,
513 gboolean save)
514 {
515 char *color_str_actual, *font_color_str_actual;
516 gboolean force_default, use_system_color;
517
518 if (save) {
519 if (note->color)
520 g_free (note->color);
521 if (note->font_color)
522 g_free (note->font_color);
523
524 note->color = color_str ? g_strdup (color_str) : NULL;
525 note->font_color = font_color_str ? g_strdup (font_color_str) : NULL;
526
527 gtk_widget_set_sensitive (note->w_color_label,
528 note->color != NULL);
529 gtk_widget_set_sensitive (note->w_font_color_label,
530 note->font_color != NULL);
531 gtk_widget_set_sensitive (note->w_color,
532 note->color != NULL);
533 gtk_widget_set_sensitive (note->w_font_color,
534 note->color != NULL);
535 }
536
537 force_default = g_settings_get_boolean (stickynotes->settings,
538 "force-default");
539 use_system_color = g_settings_get_boolean (stickynotes->settings,
540 "use-system-color");
541
542 /* If "force_default" is enabled or color_str is NULL,
543 * then we use the default color instead of color_str. */
544 if (!color_str || force_default) {
545 if (use_system_color)
546 color_str_actual = NULL;
547 else
548 color_str_actual = g_settings_get_string (stickynotes->settings,
549 "default-color");
550 } else
551 color_str_actual = g_strdup (color_str);
552
553 if (!font_color_str || force_default) {
554 if (use_system_color)
555 font_color_str_actual = NULL;
556 else
557 font_color_str_actual = g_settings_get_string (stickynotes->settings,
558 "default-font-color");
559 } else
560 font_color_str_actual = g_strdup (font_color_str);
561
562 /* Do not use custom colors if "use_system_color" is enabled */
563 if (color_str_actual) {
564 GdkRGBA colors[4];
565 gint i;
566
567 for (i = 0; i <= 3; i++) {
568 gdk_rgba_parse (&colors[i], color_str_actual);
569 colors[i].red = (colors[i].red * (10 - i)) / 10;
570 colors[i].green = (colors[i].green * (10 - i)) / 10;
571 colors[i].blue = (colors[i].blue * (10 - i)) / 10;
572 }
573
574 gtk_widget_override_background_color (note->w_window,
575 GTK_STATE_FLAG_NORMAL,
576 &colors[0]);
577 gtk_widget_override_background_color (note->w_body,
578 GTK_STATE_FLAG_NORMAL,
579 &colors[0]);
580 gtk_widget_override_background_color (note->w_lock,
581 GTK_STATE_FLAG_NORMAL,
582 &colors[0]);
583 gtk_widget_override_background_color (note->w_close,
584 GTK_STATE_FLAG_NORMAL,
585 &colors[0]);
586 gtk_widget_override_background_color (note->w_resize_se,
587 GTK_STATE_FLAG_NORMAL,
588 &colors[0]);
589 gtk_widget_override_background_color (note->w_resize_sw,
590 GTK_STATE_FLAG_NORMAL,
591 &colors[0]);
592 } else {
593 gtk_widget_override_background_color (note->w_window,
594 GTK_STATE_FLAG_NORMAL,
595 NULL);
596 gtk_widget_override_background_color (note->w_body,
597 GTK_STATE_FLAG_NORMAL,
598 NULL);
599 gtk_widget_override_background_color (note->w_lock,
600 GTK_STATE_FLAG_NORMAL,
601 NULL);
602 gtk_widget_override_background_color (note->w_close,
603 GTK_STATE_FLAG_NORMAL,
604 NULL);
605 gtk_widget_override_background_color (note->w_resize_se,
606 GTK_STATE_FLAG_NORMAL,
607 NULL);
608 gtk_widget_override_background_color (note->w_resize_sw,
609 GTK_STATE_FLAG_NORMAL,
610 NULL);
611 }
612
613 if (font_color_str_actual) {
614 GdkRGBA color;
615
616 gdk_rgba_parse (&color, font_color_str_actual);
617
618 gtk_widget_override_color (note->w_window,
619 GTK_STATE_FLAG_NORMAL,
620 &color);
621 gtk_widget_override_color (note->w_body,
622 GTK_STATE_FLAG_NORMAL,
623 &color);
624 } else {
625 gtk_widget_override_color (note->w_window,
626 GTK_STATE_FLAG_NORMAL,
627 NULL);
628 gtk_widget_override_color (note->w_body,
629 GTK_STATE_FLAG_NORMAL,
630 NULL);
631 }
632
633 if (color_str_actual)
634 g_free (color_str_actual);
635 if (font_color_str_actual)
636 g_free (font_color_str_actual);
637 }
638
639 /* Set the sticky note font */
640 void
stickynote_set_font(StickyNote * note,const gchar * font_str,gboolean save)641 stickynote_set_font (StickyNote *note,
642 const gchar *font_str,
643 gboolean save)
644 {
645 PangoFontDescription *font_desc;
646 gchar *font_str_actual;
647
648 if (save) {
649 g_free (note->font);
650 note->font = font_str ? g_strdup (font_str) : NULL;
651
652 gtk_widget_set_sensitive (note->w_font_label,
653 note->font != NULL);
654 gtk_widget_set_sensitive (note->w_font,
655 note->font != NULL);
656 }
657
658 /* If "force_default" is enabled or font_str is NULL,
659 * then we use the default font instead of font_str. */
660 if (!font_str || g_settings_get_boolean (stickynotes->settings,
661 "force-default")) {
662 if (g_settings_get_boolean (stickynotes->settings,
663 "use-system-font"))
664 font_str_actual = NULL;
665 else
666 font_str_actual = g_settings_get_string (stickynotes->settings,
667 "default-font");
668 } else
669 font_str_actual = g_strdup (font_str);
670
671 /* Do not use custom fonts if "use_system_font" is enabled */
672 font_desc = font_str_actual ?
673 pango_font_description_from_string (font_str_actual): NULL;
674
675 /* Apply the style to the widgets */
676 gtk_widget_override_font (note->w_window, font_desc);
677 gtk_widget_override_font (note->w_body, font_desc);
678
679 g_free (font_str_actual);
680 pango_font_description_free (font_desc);
681 }
682
683 /* Lock/Unlock a sticky note from editing */
684 void
stickynote_set_locked(StickyNote * note,gboolean locked)685 stickynote_set_locked (StickyNote *note,
686 gboolean locked)
687 {
688 note->locked = locked;
689
690 /* Set cursor visibility and editability */
691 gtk_text_view_set_editable (GTK_TEXT_VIEW (note->w_body),
692 !locked);
693 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (note->w_body),
694 !locked);
695
696 /* Show appropriate icon and tooltip */
697 if (locked) {
698 gtk_image_set_from_icon_name (note->img_lock,
699 STICKYNOTES_STOCK_LOCKED,
700 GTK_ICON_SIZE_MENU);
701 gtk_widget_set_tooltip_text (note->w_lock,
702 _("This note is locked."));
703 } else {
704 gtk_image_set_from_icon_name (note->img_lock,
705 STICKYNOTES_STOCK_UNLOCKED,
706 GTK_ICON_SIZE_MENU);
707 gtk_widget_set_tooltip_text (note->w_lock,
708 _("This note is unlocked."));
709 }
710
711 gtk_image_set_pixel_size (note->img_lock,
712 STICKYNOTES_ICON_SIZE);
713
714 gtk_toggle_action_set_active (note->ta_lock_toggle_item,
715 locked);
716
717 stickynotes_applet_update_menus ();
718 }
719
720 /* Show/Hide a sticky note */
721 void
stickynote_set_visible(StickyNote * note,gboolean visible)722 stickynote_set_visible (StickyNote *note,
723 gboolean visible)
724 {
725 if (visible) {
726 gtk_window_present (GTK_WINDOW (note->w_window));
727
728 if (note->x != -1 || note->y != -1)
729 gtk_window_move (GTK_WINDOW (note->w_window),
730 note->x, note->y);
731
732 /* Put the note on all workspaces if necessary. */
733 if (g_settings_get_boolean (stickynotes->settings, "sticky"))
734 gtk_window_stick (GTK_WINDOW (note->w_window));
735
736 else if (note->workspace > 0)
737 xstuff_change_workspace (GTK_WINDOW (note->w_window),
738 note->workspace - 1);
739 } else {
740 /* Hide sticky note */
741 int x, y, width, height;
742
743 stickynotes_applet_panel_icon_get_geometry (&x, &y,
744 &width, &height);
745 set_icon_geometry (gtk_widget_get_window (GTK_WIDGET (note->w_window)),
746 x, y, width, height);
747 gtk_window_iconify (GTK_WINDOW (note->w_window));
748 }
749 }
750
751 /* Add a sticky note */
752 void
stickynotes_add(GdkScreen * screen)753 stickynotes_add (GdkScreen *screen)
754 {
755 StickyNote *note;
756
757 note = stickynote_new (screen);
758
759 stickynotes->notes = g_list_append (stickynotes->notes, note);
760 stickynotes_applet_update_tooltips ();
761 stickynotes_save ();
762 stickynote_set_visible (note, TRUE);
763 }
764
765 /* Remove a sticky note with confirmation, if needed */
766 void
stickynotes_remove(StickyNote * note)767 stickynotes_remove (StickyNote *note)
768 {
769 GtkBuilder *builder;
770 GtkWidget *dialog;
771
772 builder = gtk_builder_new ();
773 gtk_builder_add_from_resource (builder,
774 GRESOURCE "sticky-notes-delete.ui",
775 NULL);
776
777 dialog = GTK_WIDGET (gtk_builder_get_object (builder,
778 "delete_dialog"));
779
780 gtk_window_set_transient_for (GTK_WINDOW (dialog),
781 GTK_WINDOW (note->w_window));
782
783 if (stickynote_get_empty (note)
784 || !g_settings_get_boolean (stickynotes->settings,
785 "confirm-deletion")
786 || gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
787
788 /* Remove the note from the linked-list of all notes */
789 stickynotes->notes = g_list_remove_all (stickynotes->notes,
790 note);
791
792 /* Destroy the note */
793 stickynote_free (note);
794
795 /* Update tooltips */
796 stickynotes_applet_update_tooltips ();
797
798 /* Save notes */
799 stickynotes_save ();
800 }
801
802 gtk_widget_destroy (dialog);
803 g_object_unref (builder);
804 }
805
806 /* Save all sticky notes in an XML configuration file */
807 gboolean
stickynotes_save_now(void)808 stickynotes_save_now (void)
809 {
810 WnckScreen *wnck_screen;
811 const gchar *title;
812 GtkTextBuffer *buffer;
813 GtkTextIter start, end;
814 gchar *body;
815
816 gint i;
817
818 /* Create a new XML document */
819 xmlDocPtr doc = xmlNewDoc (XML_CHAR ("1.0"));
820 xmlNodePtr root = xmlNewDocNode (doc, NULL, XML_CHAR ("stickynotes"), NULL);
821
822 xmlDocSetRootElement (doc, root);
823 xmlNewProp (root, XML_CHAR ("version"), XML_CHAR (VERSION));
824
825 wnck_screen = wnck_screen_get_default ();
826 wnck_screen_force_update (wnck_screen);
827
828 /* For all sticky notes */
829 for (i = 0; i < g_list_length (stickynotes->notes); i++) {
830 WnckWindow *wnck_win;
831 gulong xid = 0;
832
833 /* Access the current note in the list */
834 StickyNote *note = g_list_nth_data (stickynotes->notes, i);
835
836 /* Retrieve the window size of the note */
837 gchar *w_str = g_strdup_printf ("%d", note->w);
838 gchar *h_str = g_strdup_printf ("%d", note->h);
839
840 /* Retrieve the window position of the note */
841 gchar *x_str = g_strdup_printf ("%d", note->x);
842 gchar *y_str = g_strdup_printf ("%d", note->y);
843
844 xid = GDK_WINDOW_XID (gtk_widget_get_window (note->w_window));
845 wnck_win = wnck_window_get (xid);
846
847 if (!g_settings_get_boolean (stickynotes->settings, "sticky") && wnck_win)
848 note->workspace = 1 +
849 wnck_workspace_get_number (wnck_window_get_workspace (wnck_win));
850 else
851 note->workspace = 0;
852
853 /* Retrieve the title of the note */
854 title = gtk_label_get_text (GTK_LABEL (note->w_title));
855
856 /* Retrieve body contents of the note */
857 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (note->w_body));
858
859 gtk_text_buffer_get_bounds (buffer, &start, &end);
860 body = gtk_text_iter_get_text (&start, &end);
861
862 /* Save the note as a node in the XML document */
863 {
864 xmlNodePtr node = xmlNewTextChild (root, NULL,
865 XML_CHAR ("note"),
866 XML_CHAR (body));
867
868 xmlNewProp (node, XML_CHAR ("title"),
869 XML_CHAR (title));
870
871 if (note->color)
872 xmlNewProp (node, XML_CHAR ("color"),
873 XML_CHAR (note->color));
874
875 if (note->font_color)
876 xmlNewProp (node, XML_CHAR ("font_color"),
877 XML_CHAR (note->font_color));
878
879 if (note->font)
880 xmlNewProp (node, XML_CHAR ("font"),
881 XML_CHAR (note->font));
882
883 if (note->locked)
884 xmlNewProp (node, XML_CHAR ("locked"),
885 XML_CHAR ("true"));
886
887 xmlNewProp (node, XML_CHAR ("x"), XML_CHAR (x_str));
888 xmlNewProp (node, XML_CHAR ("y"), XML_CHAR (y_str));
889 xmlNewProp (node, XML_CHAR ("w"), XML_CHAR (w_str));
890 xmlNewProp (node, XML_CHAR ("h"), XML_CHAR (h_str));
891 if (note->workspace > 0) {
892 char *workspace_str;
893
894 workspace_str = g_strdup_printf ("%i", note->workspace);
895 xmlNewProp (node, XML_CHAR ("workspace"), XML_CHAR (workspace_str));
896 g_free (workspace_str);
897 }
898 }
899
900 /* Now that it has been saved, reset the modified flag */
901 gtk_text_buffer_set_modified (buffer, FALSE);
902
903 g_free (x_str);
904 g_free (y_str);
905 g_free (w_str);
906 g_free (h_str);
907 g_free (body);
908 }
909
910 /* The XML file is $HOME/.config/mate/stickynotes-applet,
911 most probably */
912 {
913 gchar* path = g_build_filename (g_get_user_config_dir (),
914 "mate", NULL);
915 gchar* file = g_build_filename (path, "stickynotes-applet.xml",
916 NULL);
917 g_mkdir_with_parents (path, S_IRWXU);
918 g_free (path);
919
920 xmlSaveFormatFile (file, doc, 1);
921
922 g_free (file);
923 }
924
925 xmlFreeDoc (doc);
926
927 save_scheduled = FALSE;
928
929 return FALSE;
930 }
931
932 void
stickynotes_save(void)933 stickynotes_save (void)
934 {
935 /* If a save isn't already scheduled, save everything a minute from now. */
936 if (!save_scheduled) {
937 g_timeout_add_seconds (60, (GSourceFunc) stickynotes_save_now, NULL);
938 save_scheduled = TRUE;
939 }
940 }
941
942 /* Load all sticky notes from an XML configuration file */
943 void
stickynotes_load(GdkScreen * screen)944 stickynotes_load (GdkScreen *screen)
945 {
946 xmlDocPtr doc = NULL;
947 xmlNodePtr root;
948 xmlNodePtr node;
949 /* WnckScreen *wnck_screen; */
950 GList *new_notes, *tmp1; /* Lists of StickyNote*'s */
951 GList *new_nodes; /* Lists of xmlNodePtr's */
952 int x, y, w, h;
953
954 /* The XML file is $HOME/.config/mate/stickynotes-applet, most probably */
955 gchar* file = g_build_filename (g_get_user_config_dir (),
956 "mate", "stickynotes-applet.xml", NULL);
957
958 if (g_file_test (file, G_FILE_TEST_EXISTS)) {
959 /* load file */
960 doc = xmlParseFile (file);
961 } else {
962 /* old one */
963 g_free (file);
964
965 file = g_build_filename (g_get_home_dir (),
966 ".mate2", "stickynotes_applet", NULL);
967
968 if (g_file_test (file, G_FILE_TEST_EXISTS)) {
969 /* load file */
970 doc = xmlParseFile (file);
971 }
972 }
973 g_free (file);
974
975 /* If the XML file does not exist, create a blank one */
976 if (!doc) {
977 stickynotes_save ();
978 return;
979 }
980
981 /* If the XML file is corrupted/incorrect, create a blank one */
982 root = xmlDocGetRootElement (doc);
983 if (!root || xmlStrcmp (root->name, XML_CHAR ("stickynotes"))) {
984 xmlFreeDoc (doc);
985 stickynotes_save ();
986 return;
987 }
988
989 node = root->xmlChildrenNode;
990
991 /* For all children of the root node (ie all sticky notes) */
992 new_notes = NULL;
993 new_nodes = NULL;
994 while (node) {
995 if (!xmlStrcmp (node->name, (const xmlChar *) "note")) {
996 StickyNote *note;
997
998 /* Retrieve and set the window size of the note */
999 {
1000 gchar *w_str = (gchar *)xmlGetProp (node, XML_CHAR ("w"));
1001 gchar *h_str = (gchar *)xmlGetProp (node, XML_CHAR ("h"));
1002 if (w_str && h_str) {
1003 w = atoi (w_str);
1004 h = atoi (h_str);
1005 } else {
1006 w = 0;
1007 h = 0;
1008 }
1009
1010 g_free (w_str);
1011 g_free (h_str);
1012 }
1013
1014 /* Retrieve and set the window position of the note */
1015 {
1016 gchar *x_str = (gchar *)xmlGetProp (node, XML_CHAR ("x"));
1017 gchar *y_str = (gchar *)xmlGetProp (node, XML_CHAR ("y"));
1018
1019 if (x_str && y_str) {
1020 x = atoi (x_str);
1021 y = atoi (y_str);
1022 } else {
1023 x = -1;
1024 y = -1;
1025 }
1026
1027 g_free (x_str);
1028 g_free (y_str);
1029 }
1030
1031 /* Create a new note */
1032 note = stickynote_new_aux (screen, x, y, w, h);
1033 stickynotes->notes = g_list_append (stickynotes->notes,
1034 note);
1035 new_notes = g_list_append (new_notes, note);
1036 new_nodes = g_list_append (new_nodes, node);
1037
1038 /* Retrieve and set title of the note */
1039 {
1040 gchar *title = (gchar *)xmlGetProp (node,
1041 XML_CHAR ("title"));
1042 if (title)
1043 stickynote_set_title (note, title);
1044
1045 g_free (title);
1046 }
1047
1048 /* Retrieve and set the color of the note */
1049 {
1050 gchar *color_str;
1051 gchar *font_color_str;
1052
1053 color_str = (gchar *)xmlGetProp (node, XML_CHAR ("color"));
1054 font_color_str = (gchar *)xmlGetProp (node, XML_CHAR ("font_color"));
1055
1056 if (color_str || font_color_str)
1057 stickynote_set_color (note,
1058 color_str,
1059 font_color_str,
1060 TRUE);
1061
1062 g_free (color_str);
1063 g_free (font_color_str);
1064 }
1065
1066 /* Retrieve and set the font of the note */
1067 {
1068 gchar *font_str = (gchar *)xmlGetProp (node,
1069 XML_CHAR ("font"));
1070 if (font_str)
1071 stickynote_set_font (note, font_str, TRUE);
1072
1073 g_free (font_str);
1074 }
1075
1076 /* Retrieve the workspace */
1077 {
1078 char *workspace_str;
1079
1080 workspace_str = (gchar *)xmlGetProp (node,
1081 XML_CHAR ("workspace"));
1082 if (workspace_str) {
1083 note->workspace = atoi (workspace_str);
1084 g_free (workspace_str);
1085 }
1086 }
1087
1088 /* Retrieve and set (if any) the body contents of the
1089 * note */
1090 {
1091 gchar *body = (gchar *)xmlNodeListGetString (doc,
1092 node->xmlChildrenNode,
1093 1);
1094 if (body) {
1095 GtkTextBuffer *buffer;
1096 GtkTextIter start, end;
1097
1098 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (note->w_body));
1099 gtk_text_buffer_get_bounds (buffer,
1100 &start, &end);
1101 gtk_text_buffer_insert (buffer,
1102 &start, body, -1);
1103 }
1104 g_free (body);
1105 }
1106
1107 /* Retrieve and set the locked state of the note,
1108 * by default unlocked */
1109 {
1110 gchar *locked = (gchar *)xmlGetProp (node,
1111 XML_CHAR ("locked"));
1112 if (locked)
1113 stickynote_set_locked (note,
1114 !strcmp (locked,
1115 "true"));
1116 g_free (locked);
1117 }
1118 }
1119
1120 node = node->next;
1121 }
1122
1123 tmp1 = new_notes;
1124 /*
1125 wnck_screen = wnck_screen_get_default ();
1126 wnck_screen_force_update (wnck_screen);
1127 */
1128
1129 while (tmp1) {
1130 StickyNote *note = tmp1->data;
1131
1132 stickynote_set_visible (note, stickynotes->visible);
1133 tmp1 = tmp1->next;
1134 }
1135
1136 g_list_free (new_notes);
1137 g_list_free (new_nodes);
1138
1139 xmlFreeDoc (doc);
1140 }
1141