dockapps/wmstickynotes/wmstickynotes.c
2014-10-05 19:18:49 +01:00

475 lines
14 KiB
C

/*
* $Id: wmstickynotes.c 11 2009-02-21 04:11:47Z hnc $
*
* Copyright (C) 2009 Heath Caldwell <hncaldwell@gmail.com>
*
*/
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <dirent.h>
#include <getopt.h>
#include "wmstickynotes.h"
#include "wmstickynotes.xpm"
#include "delete_button.xpm"
#include "resize_button.xpm"
#include "config.h"
#include <X11/Xlib.h>
#include <X11/extensions/shape.h>
GdkColormap *colormap;
/* The highest note id used so far (this is used when making a new note so
* that no ids are clobbered */
long int highest_note_id = 0;
/* The current note that the popup menu was shown for */
Note *current_note;
void usage()
{
printf("Usage: wmstickynotes [options]\n");
printf("\toptions:\n");
printf("\t-d [dir], --directory=[dir]\tSet directory in which to store notes\n");
printf("\t\t\t\t\tDefaults to $HOME/%s\n", default_wmstickynotes_dir);
printf("\t-v, --version\tPrint version information\n");
printf("\t-h, --help\tPrint usage\n");
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *box;
GdkColor color;
XWMHints mywmhints;
GtkWidget *main_button;
GdkPixmap *main_button_pixmap;
GdkBitmap *main_button_mask;
GtkWidget *main_button_box;
GtkWidget *color_menu;
GtkWidget *item;
GtkWidget *label;
GtkWidget *color_box;
GtkWidget *hbox;
GdkColor gcolor;
char *wmstickynotes_dir = NULL;
gboolean use_default_dir = TRUE;
int option_index = 0;
int i = 0;
struct option long_options[] = {
{"directory", required_argument, 0, 'd'},
{"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}};
for(
i = getopt_long(argc, argv, "d:vh", long_options, &option_index);
i >= 0;
i = getopt_long(argc, argv, "d:vh", long_options, &option_index)
) {
switch(i) {
case 'd':
wmstickynotes_dir = optarg;
use_default_dir = FALSE;
break;
case 'v':
printf("%s\n", PACKAGE_STRING);
printf("Copyright (C) 2009 %s\n", PACKAGE_BUGREPORT);
return 0;
case 'h':
usage();
return 0;
default:
usage();
return 1;
}
}
umask(077);
if(use_default_dir) {
wmstickynotes_dir = calloc(
strlen(default_wmstickynotes_dir) +
strlen(getenv("HOME")) + 2, sizeof(char));
strcpy(wmstickynotes_dir, getenv("HOME"));
strcat(wmstickynotes_dir, "/");
strcat(wmstickynotes_dir, default_wmstickynotes_dir);
}
if(chdir(wmstickynotes_dir)) {
if(errno == ENOENT) {
if(mkdir(wmstickynotes_dir, 0777)) {
fprintf(stderr, "Couldn't make directory: %s\n", wmstickynotes_dir);
exit(1);
}
if(chdir(wmstickynotes_dir)) {
fprintf(stderr, "Couldn't change to directory: %s\n", wmstickynotes_dir);
exit(1);
}
} else {
fprintf(stderr, "Couldn't change to directory: %s\n", wmstickynotes_dir);
exit(1);
}
}
if(use_default_dir) free(wmstickynotes_dir);
gtk_init(&argc, &argv);
colormap = gdk_colormap_new(gdk_visual_get_system(), TRUE);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_default_size(GTK_WINDOW(window), 64, 64);
box = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER (window), box);
gdk_color_parse ("#fafafa", &color);
gtk_widget_modify_bg(box, GTK_STATE_NORMAL, &color);
main_button_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &main_button_mask, NULL, wmstickynotes_xpm);
main_button = gtk_image_new_from_pixmap(main_button_pixmap, main_button_mask);
main_button_box = gtk_event_box_new();
gtk_container_add(GTK_CONTAINER(main_button_box), main_button);
gtk_container_add(GTK_CONTAINER(box), main_button_box);
color_menu = gtk_menu_new();
for(i=0; i < num_color_schemes; i++) {
item = gtk_menu_item_new();
label = gtk_label_new(color_schemes[i].name);
color_box = gtk_event_box_new();
gtk_widget_set_size_request(color_box, 15, -1);
hbox = gtk_hbox_new(FALSE, 4);
gdk_color_parse(color_schemes[i].top, &gcolor);
gtk_widget_modify_bg(color_box, GTK_STATE_NORMAL, &gcolor);
gtk_widget_modify_bg(color_box, GTK_STATE_PRELIGHT, &gcolor);
gtk_container_add(GTK_CONTAINER(item), hbox);
gtk_box_pack_start(GTK_BOX(hbox), color_box, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
gtk_menu_shell_append(GTK_MENU_SHELL(color_menu), item);
g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(new_note_from_menu), &color_schemes[i]);
}
gtk_widget_show_all(GTK_WIDGET(color_menu));
gtk_widget_show_all(window);
mywmhints.initial_state = WithdrawnState;
mywmhints.icon_window = GDK_WINDOW_XWINDOW(box->window);
mywmhints.icon_x = 0;
mywmhints.icon_y = 0;
mywmhints.window_group = GDK_WINDOW_XWINDOW(window->window);
mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
XSetWMHints(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(window->window), &mywmhints);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(main_button_box), "button-press-event", G_CALLBACK(main_button_pressed), color_menu);
read_old_notes();
gtk_main();
return 0;
}
void delete_note(GtkWidget *widget, Note *note)
{
char *filename;
asprintf(&filename, "%d", note->id);
unlink(filename);
free(note);
}
void save_note(GtkWidget *widget, Note *note)
{
FILE *file;
char *filename;
GtkTextBuffer *text_buffer;
GtkTextIter start;
GtkTextIter end;
gchar *text;
text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(note->text_widget));
gtk_text_buffer_get_start_iter(text_buffer, &start);
gtk_text_buffer_get_end_iter(text_buffer, &end);
text = gtk_text_buffer_get_text(text_buffer, &start, &end, FALSE);
asprintf(&filename, "%d", note->id);
file = fopen(filename, "w");
free(filename);
fprintf(
file, "%d,%d,%d,%d,%d,%d,%s\n%s",
note->x, note->y, note->width, note->height, 0, 0, note->scheme->name, text);
fclose(file);
g_free(text);
}
gboolean note_configure_event(GtkWidget *window, GdkEventConfigure *event, Note *note)
{
note->x = event->x;
note->y = event->y;
note->width = event->width;
note->height = event->height;
save_note(window, note);
return FALSE;
}
void bar_pressed(GtkWidget *widget, GdkEventButton *event, Note *note)
{
gtk_window_begin_move_drag(GTK_WINDOW(note->window), event->button, event->x_root, event->y_root, event->time);
}
void resize_button_pressed(GtkWidget *widget, GdkEventButton *event, Note *note)
{
gtk_window_begin_resize_drag(GTK_WINDOW(note->window), GDK_WINDOW_EDGE_SOUTH_EAST, event->button, event->x_root, event->y_root, event->time);
}
void delete_button_pressed(GtkWidget *widget, GdkEventButton *event, GtkWidget *window)
{
if(event->button != 1) return;
gtk_widget_destroy(window);
}
void main_button_pressed(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
if(event->button == 1) {
create_note(NULL, &color_schemes[0]);
} else if(event->button == 3) {
gtk_menu_popup(GTK_MENU(user_data), NULL, NULL, NULL, NULL, event->button, event->time);
}
}
void create_note(Note *old_note, ColorScheme *scheme)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *top_hbox;
GtkWidget *mid_hbox;
GtkWidget *bottom_bar;
GtkWidget *bottom_hbox;
GtkWidget *top_bar;
GtkWidget *delete_button;
GdkPixmap *delete_button_pixmap;
GdkBitmap *delete_button_mask;
GtkWidget *resize_button;
GdkPixmap *resize_button_pixmap;
GdkBitmap *resize_button_mask;
GtkTextBuffer *text_buffer;
Note *note;
note = old_note ? old_note : malloc(sizeof(Note));
if(!old_note) {
highest_note_id++;
note->id = highest_note_id;
note->scheme = scheme;
}
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
gtk_window_set_default_size(GTK_WINDOW(window), 150, 150);
if(!old_note) {
note->text_widget = gtk_text_view_new_with_buffer(NULL);
}
text_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(note->text_widget));
note->window = window;
vbox = gtk_vbox_new(FALSE, 0);
top_hbox = gtk_hbox_new(FALSE, 0);
mid_hbox = gtk_hbox_new(FALSE, 0);
bottom_hbox = gtk_hbox_new(FALSE, 0);
top_bar = gtk_label_new("");
note->top_bar_box = gtk_event_box_new();
gtk_widget_set_size_request(top_bar, -1, 10);
bottom_bar = gtk_label_new("");
gtk_widget_set_size_request(bottom_bar, -1, 8);
delete_button_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &delete_button_mask, NULL, delete_button_xpm);
delete_button = gtk_image_new_from_pixmap(delete_button_pixmap, delete_button_mask);
note->delete_button_box = gtk_event_box_new();
gtk_widget_set_size_request(note->delete_button_box, 10, 10);
resize_button_pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap, &resize_button_mask, NULL, resize_button_xpm);
resize_button = gtk_image_new_from_pixmap(resize_button_pixmap, resize_button_mask);
note->resize_button_box = gtk_event_box_new();
set_note_color(note, note->scheme);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_container_add(GTK_CONTAINER(note->top_bar_box), top_bar);
gtk_container_add(GTK_CONTAINER(note->delete_button_box), delete_button);
gtk_container_add(GTK_CONTAINER(note->resize_button_box), resize_button);
gtk_box_pack_start(GTK_BOX(top_hbox), note->top_bar_box, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(top_hbox), note->delete_button_box, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(mid_hbox), note->text_widget, TRUE, TRUE, 2);
gtk_box_pack_start(GTK_BOX(bottom_hbox), bottom_bar, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(bottom_hbox), note->resize_button_box, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), top_hbox, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), mid_hbox, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(vbox), bottom_hbox, FALSE, FALSE, 0);
gtk_widget_show_all(window);
if(old_note) {
gtk_window_resize(GTK_WINDOW(window), old_note->width, old_note->height);
gtk_window_move(GTK_WINDOW(window), old_note->x, old_note->y);
} else {
gtk_window_get_position(GTK_WINDOW(window), &(note->x), &(note->y));
gtk_window_get_size(GTK_WINDOW(window), &(note->width), &(note->height));
}
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(delete_note), note);
g_signal_connect(G_OBJECT(window), "configure-event", G_CALLBACK(note_configure_event), note);
g_signal_connect(G_OBJECT(note->delete_button_box), "button-press-event", G_CALLBACK(delete_button_pressed), window);
g_signal_connect(G_OBJECT(note->resize_button_box), "button-press-event", G_CALLBACK(resize_button_pressed), note);
g_signal_connect(G_OBJECT(text_buffer), "changed", G_CALLBACK(save_note), note);
g_signal_connect(G_OBJECT(note->top_bar_box), "button-press-event", G_CALLBACK(bar_pressed), note);
g_signal_connect(G_OBJECT(note->text_widget), "populate-popup", G_CALLBACK(populate_note_popup), note);
}
void read_old_notes()
{
Note *note;
GtkTextBuffer *text_buffer;
GtkTextIter iter;
DIR *dir = opendir(".");
FILE *file;
struct dirent *entry;
int reserved1;
int reserved2;
int i;
char buffer[256];
rewinddir(dir);
while((entry = readdir(dir)) != NULL) {
/* Check if it is a valid note name */
for(i=0; entry->d_name[i]; i++) {
if(entry->d_name[i] < '0' || entry->d_name[i] > '9') break;
}
if(i < strlen(entry->d_name)) continue;
file = fopen(entry->d_name, "r");
note = malloc(sizeof(Note));
note->id = atoi(entry->d_name);
if(note->id > highest_note_id) highest_note_id = note->id;
fscanf(file, "%d,%d,%d,%d,%d,%d,",
&(note->x), &(note->y), &(note->width), &(note->height),
&reserved1, &reserved2);
/* Get color name */
fgets(buffer, 256, file);
/* Replace the newline with a null char */
buffer[strlen(buffer) - 1] = '\0';
for(i=num_color_schemes; i > 0; i--) {
if(!strcmp(color_schemes[i].name, buffer)) break;
}
note->scheme = &color_schemes[i];
text_buffer = gtk_text_buffer_new(NULL);
while(fgets(buffer, 256, file)) {
gtk_text_buffer_get_end_iter(text_buffer, &iter);
gtk_text_buffer_insert(text_buffer, &iter, buffer, -1);
}
note->text_widget = gtk_text_view_new_with_buffer(text_buffer);
create_note(note, note->scheme);
fclose(file);
}
closedir(dir);
}
void populate_note_popup(GtkTextView *entry, GtkMenu *menu, Note *note)
{
GtkWidget *color_menu;
GtkWidget *color_item;
GtkWidget *item;
GtkWidget *label;
GtkWidget *color_box;
GtkWidget *hbox;
GdkColor gcolor;
int i;
color_menu = gtk_menu_new();
color_item = gtk_menu_item_new_with_label("Color");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(color_item), color_menu);
gtk_menu_shell_prepend(GTK_MENU_SHELL(menu), color_item);
current_note = note;
for(i=0; i < num_color_schemes; i++) {
item = gtk_menu_item_new();
label = gtk_label_new(color_schemes[i].name);
color_box = gtk_event_box_new();
gtk_widget_set_size_request(color_box, 15, -1);
hbox = gtk_hbox_new(FALSE, 4);
gdk_color_parse(color_schemes[i].top, &gcolor);
gtk_widget_modify_bg(color_box, GTK_STATE_NORMAL, &gcolor);
gtk_widget_modify_bg(color_box, GTK_STATE_PRELIGHT, &gcolor);
gtk_container_add(GTK_CONTAINER(item), hbox);
gtk_box_pack_start(GTK_BOX(hbox), color_box, FALSE, FALSE, 0);
gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
gtk_menu_shell_append(GTK_MENU_SHELL(color_menu), item);
g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(set_current_note_color), &color_schemes[i]);
}
gtk_widget_show_all(GTK_WIDGET(menu));
}
void set_current_note_color(GtkMenuItem *menuitem, ColorScheme *scheme)
{
set_note_color(current_note, scheme);
save_note(NULL, current_note);
}
void new_note_from_menu(GtkMenuItem *menuitem, ColorScheme *scheme)
{
create_note(NULL, scheme);
}
void set_note_color(Note *note, ColorScheme *scheme)
{
GdkColor gcolor;
note->scheme = scheme;
gdk_color_parse(scheme->top, &gcolor);
gtk_widget_modify_bg(note->top_bar_box, GTK_STATE_NORMAL, &gcolor);
gtk_widget_modify_bg(note->delete_button_box, GTK_STATE_NORMAL, &gcolor);
gdk_color_parse(scheme->background, &gcolor);
gtk_widget_modify_base(note->text_widget, GTK_STATE_NORMAL, &gcolor);
gtk_widget_modify_bg(note->window, GTK_STATE_NORMAL, &gcolor);
gtk_widget_modify_bg(note->resize_button_box, GTK_STATE_NORMAL, &gcolor);
}