2 * $Id: wmstickynotes.c 11 2009-02-21 04:11:47Z hnc $
4 * Copyright (C) 2009 Heath Caldwell <hncaldwell@gmail.com>
15 #include <sys/types.h>
20 #include "wmstickynotes.h"
21 #include "wmstickynotes.xpm"
22 #include "delete_button.xpm"
23 #include "resize_button.xpm"
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 */
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
[])
56 GtkWidget
*main_button
;
57 GdkPixmap
*main_button_pixmap
;
58 GdkBitmap
*main_button_mask
;
59 GtkWidget
*main_button_box
;
60 GtkWidget
*color_menu
;
66 char *wmstickynotes_dir
= NULL
;
67 gboolean use_default_dir
= TRUE
;
71 struct option long_options
[] = {
72 {"directory", required_argument
, 0, 'd'},
73 {"version", no_argument
, 0, 'v'},
74 {"help", no_argument
, 0, 'h'},
78 i
= getopt_long(argc
, argv
, "d:vh", long_options
, &option_index
);
80 i
= getopt_long(argc
, argv
, "d:vh", long_options
, &option_index
)
84 wmstickynotes_dir
= optarg
;
85 use_default_dir
= FALSE
;
88 printf("%s\n", PACKAGE_STRING
);
89 printf("Copyright (C) 2009 %s\n", PACKAGE_BUGREPORT
);
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
);
117 if(chdir(wmstickynotes_dir
)) {
118 fprintf(stderr
, "Couldn't change to directory: %s\n", wmstickynotes_dir
);
122 fprintf(stderr
, "Couldn't change to directory: %s\n", wmstickynotes_dir
);
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
);
190 void delete_note(GtkWidget
*widget
, Note
*note
)
193 asprintf(&filename
, "%d", note
->id
);
198 void save_note(GtkWidget
*widget
, Note
*note
)
202 GtkTextBuffer
*text_buffer
;
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");
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
);
225 gboolean
note_configure_event(GtkWidget
*window
, GdkEventConfigure
*event
, Note
*note
)
229 note
->width
= event
->width
;
230 note
->height
= event
->height
;
231 save_note(window
, note
);
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
)
267 GtkWidget
*bottom_bar
;
268 GtkWidget
*bottom_hbox
;
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
;
280 note
= old_note
? old_note
: malloc(sizeof(Note
));
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);
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
);
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
);
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()
355 GtkTextBuffer
*text_buffer
;
357 DIR *dir
= opendir(".");
359 struct dirent
*entry
;
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
);
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
);
409 void populate_note_popup(GtkTextView
*entry
, GtkMenu
*menu
, Note
*note
)
411 GtkWidget
*color_menu
;
412 GtkWidget
*color_item
;
415 GtkWidget
*color_box
;
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
);
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
)
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
);