wmbiff: Add missing include.
[dockapps.git] / wmstickynotes / wmstickynotes.c
blobeb6d02c553112d7f93e00cc6f44e6ca403c2825c
1 /*
2 * $Id: wmstickynotes.c 11 2009-02-21 04:11:47Z hnc $
4 * Copyright (C) 2009 Heath Caldwell <hncaldwell@gmail.com>
6 */
8 #include <gtk/gtk.h>
9 #include <gdk/gdkx.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <errno.h>
17 #include <dirent.h>
18 #include <getopt.h>
20 #include "wmstickynotes.h"
21 #include "wmstickynotes.xpm"
22 #include "delete_button.xpm"
23 #include "resize_button.xpm"
24 #include "config.h"
26 #include <X11/Xlib.h>
27 #include <X11/extensions/shape.h>
29 GdkColormap *colormap;
31 /* The highest note id used so far (this is used when making a new note so
32 * that no ids are clobbered */
33 long int highest_note_id = 0;
35 /* The current note that the popup menu was shown for */
36 Note *current_note;
40 void usage()
42 printf("Usage: wmstickynotes [options]\n");
43 printf("\toptions:\n");
44 printf("\t-d [dir], --directory=[dir]\tSet directory in which to store notes\n");
45 printf("\t\t\t\t\tDefaults to $HOME/%s\n", default_wmstickynotes_dir);
46 printf("\t-v, --version\tPrint version information\n");
47 printf("\t-h, --help\tPrint usage\n");
50 int main(int argc, char *argv[])
52 GtkWidget *window;
53 GtkWidget *box;
54 GdkColor color;
55 XWMHints mywmhints;
56 GtkWidget *main_button;
57 GdkPixmap *main_button_pixmap;
58 GdkBitmap *main_button_mask;
59 GtkWidget *main_button_box;
60 GtkWidget *color_menu;
61 GtkWidget *item;
62 GtkWidget *label;
63 GtkWidget *color_box;
64 GtkWidget *hbox;
65 GdkColor gcolor;
66 char *wmstickynotes_dir = NULL;
67 gboolean use_default_dir = TRUE;
68 int option_index = 0;
69 int i = 0;
71 struct option long_options[] = {
72 {"directory", required_argument, 0, 'd'},
73 {"version", no_argument, 0, 'v'},
74 {"help", no_argument, 0, 'h'},
75 {0, 0, 0, 0}};
77 for(
78 i = getopt_long(argc, argv, "d:vh", long_options, &option_index);
79 i >= 0;
80 i = getopt_long(argc, argv, "d:vh", long_options, &option_index)
81 ) {
82 switch(i) {
83 case 'd':
84 wmstickynotes_dir = optarg;
85 use_default_dir = FALSE;
86 break;
87 case 'v':
88 printf("%s\n", PACKAGE_STRING);
89 printf("Copyright (C) 2009 %s\n", PACKAGE_BUGREPORT);
90 return 0;
91 case 'h':
92 usage();
93 return 0;
94 default:
95 usage();
96 return 1;
100 umask(077);
102 if(use_default_dir) {
103 wmstickynotes_dir = calloc(
104 strlen(default_wmstickynotes_dir) +
105 strlen(getenv("HOME")) + 2, sizeof(char));
106 strcpy(wmstickynotes_dir, getenv("HOME"));
107 strcat(wmstickynotes_dir, "/");
108 strcat(wmstickynotes_dir, default_wmstickynotes_dir);
111 if(chdir(wmstickynotes_dir)) {
112 if(errno == ENOENT) {
113 if(mkdir(wmstickynotes_dir, 0777)) {
114 fprintf(stderr, "Couldn't make directory: %s\n", wmstickynotes_dir);
115 exit(1);
117 if(chdir(wmstickynotes_dir)) {
118 fprintf(stderr, "Couldn't change to directory: %s\n", wmstickynotes_dir);
119 exit(1);
121 } else {
122 fprintf(stderr, "Couldn't change to directory: %s\n", wmstickynotes_dir);
123 exit(1);
127 if(use_default_dir) free(wmstickynotes_dir);
129 gtk_init(&argc, &argv);
131 colormap = gdk_colormap_new(gdk_visual_get_system(), TRUE);
133 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
134 gtk_window_set_default_size(GTK_WINDOW(window), 64, 64);
136 box = gtk_event_box_new();
137 gtk_container_add(GTK_CONTAINER (window), box);
139 gdk_color_parse ("#fafafa", &color);
140 gtk_widget_modify_bg(box, GTK_STATE_NORMAL, &color);
142 main_button_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &main_button_mask, NULL, wmstickynotes_xpm);
143 main_button = gtk_image_new_from_pixmap(main_button_pixmap, main_button_mask);
144 main_button_box = gtk_event_box_new();
145 gtk_container_add(GTK_CONTAINER(main_button_box), main_button);
146 gtk_container_add(GTK_CONTAINER(box), main_button_box);
148 color_menu = gtk_menu_new();
150 for(i=0; i < num_color_schemes; i++) {
151 item = gtk_menu_item_new();
152 label = gtk_label_new(color_schemes[i].name);
153 color_box = gtk_event_box_new();
154 gtk_widget_set_size_request(color_box, 15, -1);
155 hbox = gtk_hbox_new(FALSE, 4);
157 gdk_color_parse(color_schemes[i].top, &gcolor);
158 gtk_widget_modify_bg(color_box, GTK_STATE_NORMAL, &gcolor);
159 gtk_widget_modify_bg(color_box, GTK_STATE_PRELIGHT, &gcolor);
161 gtk_container_add(GTK_CONTAINER(item), hbox);
162 gtk_box_pack_start(GTK_BOX(hbox), color_box, FALSE, FALSE, 0);
163 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
165 gtk_menu_shell_append(GTK_MENU_SHELL(color_menu), item);
166 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(new_note_from_menu), &color_schemes[i]);
169 gtk_widget_show_all(GTK_WIDGET(color_menu));
170 gtk_widget_show_all(window);
172 mywmhints.initial_state = WithdrawnState;
173 mywmhints.icon_window = GDK_WINDOW_XWINDOW(box->window);
174 mywmhints.icon_x = 0;
175 mywmhints.icon_y = 0;
176 mywmhints.window_group = GDK_WINDOW_XWINDOW(window->window);
177 mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
179 XSetWMHints(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window->window), &mywmhints);
181 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
182 g_signal_connect(G_OBJECT(main_button_box), "button-press-event", G_CALLBACK(main_button_pressed), color_menu);
184 read_old_notes();
185 gtk_main();
187 return 0;
190 void delete_note(GtkWidget *widget, Note *note)
192 char *filename;
193 asprintf(&filename, "%d", note->id);
194 unlink(filename);
195 free(note);
198 void save_note(GtkWidget *widget, Note *note)
200 FILE *file;
201 char *filename;
202 GtkTextBuffer *text_buffer;
203 GtkTextIter start;
204 GtkTextIter end;
205 gchar *text;
207 text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(note->text_widget));
208 gtk_text_buffer_get_start_iter(text_buffer, &start);
209 gtk_text_buffer_get_end_iter(text_buffer, &end);
211 text = gtk_text_buffer_get_text(text_buffer, &start, &end, FALSE);
213 asprintf(&filename, "%d", note->id);
214 file = fopen(filename, "w");
215 free(filename);
217 fprintf(
218 file, "%d,%d,%d,%d,%d,%d,%s\n%s",
219 note->x, note->y, note->width, note->height, 0, 0, note->scheme->name, text);
220 fclose(file);
222 g_free(text);
225 gboolean note_configure_event(GtkWidget *window, GdkEventConfigure *event, Note *note)
227 note->x = event->x;
228 note->y = event->y;
229 note->width = event->width;
230 note->height = event->height;
231 save_note(window, note);
232 return FALSE;
235 void bar_pressed(GtkWidget *widget, GdkEventButton *event, Note *note)
237 gtk_window_begin_move_drag(GTK_WINDOW(note->window), event->button, event->x_root, event->y_root, event->time);
240 void resize_button_pressed(GtkWidget *widget, GdkEventButton *event, Note *note)
242 gtk_window_begin_resize_drag(GTK_WINDOW(note->window), GDK_WINDOW_EDGE_SOUTH_EAST, event->button, event->x_root, event->y_root, event->time);
245 void delete_button_pressed(GtkWidget *widget, GdkEventButton *event, GtkWidget *window)
247 if(event->button != 1) return;
249 gtk_widget_destroy(window);
252 void main_button_pressed(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
254 if(event->button == 1) {
255 create_note(NULL, &color_schemes[0]);
256 } else if(event->button == 3) {
257 gtk_menu_popup(GTK_MENU(user_data), NULL, NULL, NULL, NULL, event->button, event->time);
261 void create_note(Note *old_note, ColorScheme *scheme)
263 GtkWidget *window;
264 GtkWidget *vbox;
265 GtkWidget *top_hbox;
266 GtkWidget *mid_hbox;
267 GtkWidget *bottom_bar;
268 GtkWidget *bottom_hbox;
269 GtkWidget *top_bar;
270 GtkWidget *delete_button;
271 GdkPixmap *delete_button_pixmap;
272 GdkBitmap *delete_button_mask;
273 GtkWidget *resize_button;
274 GdkPixmap *resize_button_pixmap;
275 GdkBitmap *resize_button_mask;
276 GtkTextBuffer *text_buffer;
278 Note *note;
280 note = old_note ? old_note : malloc(sizeof(Note));
282 if(!old_note) {
283 highest_note_id++;
284 note->id = highest_note_id;
285 note->scheme = scheme;
288 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
289 gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
290 gtk_window_set_default_size(GTK_WINDOW(window), 150, 150);
292 if(!old_note) {
293 note->text_widget = gtk_text_view_new_with_buffer(NULL);
295 text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(note->text_widget));
297 note->window = window;
299 vbox = gtk_vbox_new(FALSE, 0);
300 top_hbox = gtk_hbox_new(FALSE, 0);
301 mid_hbox = gtk_hbox_new(FALSE, 0);
302 bottom_hbox = gtk_hbox_new(FALSE, 0);
303 top_bar = gtk_label_new("");
304 note->top_bar_box = gtk_event_box_new();
305 gtk_widget_set_size_request(top_bar, -1, 10);
306 bottom_bar = gtk_label_new("");
307 gtk_widget_set_size_request(bottom_bar, -1, 8);
309 delete_button_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &delete_button_mask, NULL, delete_button_xpm);
310 delete_button = gtk_image_new_from_pixmap(delete_button_pixmap, delete_button_mask);
311 note->delete_button_box = gtk_event_box_new();
312 gtk_widget_set_size_request(note->delete_button_box, 10, 10);
314 resize_button_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &resize_button_mask, NULL, resize_button_xpm);
315 resize_button = gtk_image_new_from_pixmap(resize_button_pixmap, resize_button_mask);
316 note->resize_button_box = gtk_event_box_new();
318 set_note_color(note, note->scheme);
320 gtk_container_add(GTK_CONTAINER(window), vbox);
321 gtk_container_add(GTK_CONTAINER(note->top_bar_box), top_bar);
322 gtk_container_add(GTK_CONTAINER(note->delete_button_box), delete_button);
323 gtk_container_add(GTK_CONTAINER(note->resize_button_box), resize_button);
324 gtk_box_pack_start(GTK_BOX(top_hbox), note->top_bar_box, TRUE, TRUE, 0);
325 gtk_box_pack_start(GTK_BOX(top_hbox), note->delete_button_box, FALSE, FALSE, 0);
326 gtk_box_pack_start(GTK_BOX(mid_hbox), note->text_widget, TRUE, TRUE, 2);
327 gtk_box_pack_start(GTK_BOX(bottom_hbox), bottom_bar, TRUE, TRUE, 0);
328 gtk_box_pack_start(GTK_BOX(bottom_hbox), note->resize_button_box, FALSE, FALSE, 0);
329 gtk_box_pack_start(GTK_BOX(vbox), top_hbox, FALSE, FALSE, 0);
330 gtk_box_pack_start(GTK_BOX(vbox), mid_hbox, TRUE, TRUE, 0);
331 gtk_box_pack_start(GTK_BOX(vbox), bottom_hbox, FALSE, FALSE, 0);
333 gtk_widget_show_all(window);
335 if(old_note) {
336 gtk_window_resize(GTK_WINDOW(window), old_note->width, old_note->height);
337 gtk_window_move(GTK_WINDOW(window), old_note->x, old_note->y);
338 } else {
339 gtk_window_get_position(GTK_WINDOW(window), &(note->x), &(note->y));
340 gtk_window_get_size(GTK_WINDOW(window), &(note->width), &(note->height));
343 g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(delete_note), note);
344 g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(note_configure_event), note);
345 g_signal_connect(G_OBJECT(note->delete_button_box), "button-press-event", G_CALLBACK(delete_button_pressed), window);
346 g_signal_connect(G_OBJECT(note->resize_button_box), "button-press-event", G_CALLBACK(resize_button_pressed), note);
347 g_signal_connect(G_OBJECT(text_buffer), "changed", G_CALLBACK(save_note), note);
348 g_signal_connect(G_OBJECT(note->top_bar_box), "button-press-event", G_CALLBACK(bar_pressed), note);
349 g_signal_connect(G_OBJECT(note->text_widget), "populate-popup", G_CALLBACK(populate_note_popup), note);
352 void read_old_notes()
354 Note *note;
355 GtkTextBuffer *text_buffer;
356 GtkTextIter iter;
357 DIR *dir = opendir(".");
358 FILE *file;
359 struct dirent *entry;
360 int reserved1;
361 int reserved2;
362 int i;
363 char buffer[256];
365 rewinddir(dir);
366 while((entry = readdir(dir)) != NULL) {
367 /* Check if it is a valid note name */
368 for(i=0; entry->d_name[i]; i++) {
369 if(entry->d_name[i] < '0' || entry->d_name[i] > '9') break;
371 if(i < strlen(entry->d_name)) continue;
373 file = fopen(entry->d_name, "r");
374 note = malloc(sizeof(Note));
376 note->id = atoi(entry->d_name);
377 if(note->id > highest_note_id) highest_note_id = note->id;
379 fscanf(file, "%d,%d,%d,%d,%d,%d,",
380 &(note->x), &(note->y), &(note->width), &(note->height),
381 &reserved1, &reserved2);
383 /* Get color name */
384 fgets(buffer, 256, file);
385 /* Replace the newline with a null char */
386 buffer[strlen(buffer) - 1] = '\0';
388 for(i=num_color_schemes; i > 0; i--) {
389 if(!strcmp(color_schemes[i].name, buffer)) break;
391 note->scheme = &color_schemes[i];
393 text_buffer = gtk_text_buffer_new(NULL);
394 while(fgets(buffer, 256, file)) {
395 gtk_text_buffer_get_end_iter(text_buffer, &iter);
396 gtk_text_buffer_insert(text_buffer, &iter, buffer, -1);
399 note->text_widget = gtk_text_view_new_with_buffer(text_buffer);
401 create_note(note, note->scheme);
403 fclose(file);
406 closedir(dir);
409 void populate_note_popup(GtkTextView *entry, GtkMenu *menu, Note *note)
411 GtkWidget *color_menu;
412 GtkWidget *color_item;
413 GtkWidget *item;
414 GtkWidget *label;
415 GtkWidget *color_box;
416 GtkWidget *hbox;
417 GdkColor gcolor;
418 int i;
420 color_menu = gtk_menu_new();
421 color_item = gtk_menu_item_new_with_label("Color");
423 gtk_menu_item_set_submenu(GTK_MENU_ITEM(color_item), color_menu);
424 gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), color_item);
426 current_note = note;
427 for(i=0; i < num_color_schemes; i++) {
428 item = gtk_menu_item_new();
429 label = gtk_label_new(color_schemes[i].name);
430 color_box = gtk_event_box_new();
431 gtk_widget_set_size_request(color_box, 15, -1);
432 hbox = gtk_hbox_new(FALSE, 4);
434 gdk_color_parse(color_schemes[i].top, &gcolor);
435 gtk_widget_modify_bg(color_box, GTK_STATE_NORMAL, &gcolor);
436 gtk_widget_modify_bg(color_box, GTK_STATE_PRELIGHT, &gcolor);
438 gtk_container_add(GTK_CONTAINER(item), hbox);
439 gtk_box_pack_start(GTK_BOX(hbox), color_box, FALSE, FALSE, 0);
440 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
442 gtk_menu_shell_append(GTK_MENU_SHELL(color_menu), item);
443 g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(set_current_note_color), &color_schemes[i]);
446 gtk_widget_show_all(GTK_WIDGET(menu));
449 void set_current_note_color(GtkMenuItem *menuitem, ColorScheme *scheme)
451 set_note_color(current_note, scheme);
452 save_note(NULL, current_note);
455 void new_note_from_menu(GtkMenuItem *menuitem, ColorScheme *scheme)
457 create_note(NULL, scheme);
460 void set_note_color(Note *note, ColorScheme *scheme)
462 GdkColor gcolor;
464 note->scheme = scheme;
466 gdk_color_parse(scheme->top, &gcolor);
467 gtk_widget_modify_bg(note->top_bar_box, GTK_STATE_NORMAL, &gcolor);
468 gtk_widget_modify_bg(note->delete_button_box, GTK_STATE_NORMAL, &gcolor);
470 gdk_color_parse(scheme->background, &gcolor);
471 gtk_widget_modify_base(note->text_widget, GTK_STATE_NORMAL, &gcolor);
472 gtk_widget_modify_bg(note->window, GTK_STATE_NORMAL, &gcolor);
473 gtk_widget_modify_bg(note->resize_button_box, GTK_STATE_NORMAL, &gcolor);