Merge lp:~ghugesss/xpad/code_refactor into lp:xpad

Proposed by Sagar Ghuge
Status: Needs review
Proposed branch: lp:~ghugesss/xpad/code_refactor
Merge into: lp:xpad
Diff against target: 8138 lines (+3350/-3252)
21 files modified
src/fio.h (+7/-3)
src/help.c (+3/-1)
src/help.h (+3/-3)
src/prefix.h (+3/-3)
src/xpad-app.c (+239/-232)
src/xpad-grip-tool-item.c (+38/-39)
src/xpad-pad-group.c (+15/-11)
src/xpad-pad-properties.c (+144/-143)
src/xpad-pad.c (+1200/-1203)
src/xpad-periodic.c (+230/-207)
src/xpad-periodic.h (+7/-3)
src/xpad-preferences.c (+477/-491)
src/xpad-session-manager.c (+60/-57)
src/xpad-session-manager.h (+4/-0)
src/xpad-settings.c (+225/-210)
src/xpad-text-buffer.c (+137/-124)
src/xpad-text-view.c (+99/-100)
src/xpad-toolbar.c (+279/-269)
src/xpad-tray.c (+85/-75)
src/xpad-tray.h (+4/-0)
src/xpad-undo.c (+91/-78)
To merge this branch: bzr merge lp:~ghugesss/xpad/code_refactor
Reviewer Review Type Date Requested Status
Arthur Borsboom code review no testing Needs Fixing
Review via email: mp+233722@code.launchpad.net

Description of the change

https://wiki.gnome.org/Projects/GTK%2B/BestPractices

As our app is under GNOME so we need to follow the global coding style and also follow the header includes for .c files.

I have tested a code and working fine. As I know you will going to see lot of changes, so from onwards before accepting any patch from other contributors we ask him to also follow the standard coding style.

To post a comment you must log in.
Revision history for this message
Arthur Borsboom (arthurborsboom) wrote :

Hi Sagar,

I went through most of the code changes.
Some things I dislike, some things I like.
Let's see if we can agree on the parts.
I summarize below what I would like to see different.
Feel free to disagree and explain,

1. Split and group changes (and merge requests)

When working with other developers, in general it is better to produce small changes.
And if the changes are bigger, than at least group the different changes together.
In this merge proposal there are many different changes, with some I agree (which I would like to merge) and some I disagree, which I would like to request fixing.

Splitting the changes also makes it easier to find issues introduced by changes. It also makes it easier to undo a change.

So my request is to split the different changes. Below I try to do a start, since I discuss each group of changes by subject.

2. Order of includes

Agree totally. I would like to merge this directly.

3. Improving head guards

I Agree totally. I would like to merge this directly.

4. Improving function declarations by G_BEGIN_DECLS and G_END_DECLS

I Agree totally. I would like to merge this directly.

5. Removal of function prototypes by reordering functions

I am in a split here.
I agree that it is nicer and easier to maintain if these are removed.
I disagree since it sometimes make readability and therefore maintainability harder.

So, only if the readability of the code stays more or less the same, I am in favor of this. Two examples:

I do like the removal of the forward declaration in xpad-pad-group.c

I dislike reading the xpad-pad.c and xpad-app.c from the bottom to the top (instead of the other way around), and therefore I don't like this to be changed.

6. Reformatting of function parameters, each parameter on a new line.

I strongly dislike this. In my opinion this makes reading the code much harder.

I guess it comes from the old-fashioned Linux kernel coding rule: 80 character limit. I used to dislike it and I still dislike it. These days almost each developer has a screen with at least 200 characters if not 500.

Only when the function declaration becomes extremely long, breaking this line in two or three pieces might be better.

7. Reformatting of function and return type on a new line.

I guess this is better. This might be my Java coding habit from the old days.

/* good */
static void
xpad_undo_class_init (XpadUndoClass *klass)

/* bad */
static void xpad_undo_class_init (XpadUndoClass *klass)

I prefer the one defined by me as 'bad', but I don't think it changes readability a lot and the code conforms to the best practice.

***

In general, best practices are good, but are not the law. In my opinion if you have a good reason to disagree with the best practice, it is okay.

For me, most of the disagreements above have to do with readability and maintainability. And since I (we) are maintaining the software, I like to do this as easy as possible.

Again, everything is open for discussing.

Nevertheless, I would like you to start with discussion point 1.
Then I can merge all the subjects we agree on and we can discuss the others after that.

Cheers,
Arthur.

review: Needs Fixing (code review no testing)

Unmerged revisions

705. By Sagar Ghuge

Typo corrected.

704. By Sagar Ghuge

Code refactoring done.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/fio.h'
--- src/fio.h 2014-06-15 10:02:50 +0000
+++ src/fio.h 2014-09-08 13:22:52 +0000
@@ -19,11 +19,13 @@
1919
20*/20*/
2121
22#ifndef _FIO_H_22#ifndef __FIO_H__
23#define _FIO_H_23#define __FIO_H__
2424
25#include <glib.h>25#include <glib.h>
2626
27G_BEGIN_DECLS
28
27gchar *fio_get_file (const gchar *name);29gchar *fio_get_file (const gchar *name);
28gboolean fio_set_file (const gchar *name, const gchar *value);30gboolean fio_set_file (const gchar *name, const gchar *value);
29void fio_remove_file (const gchar *filename);31void fio_remove_file (const gchar *filename);
@@ -35,4 +37,6 @@
3537
36gchar *fio_unique_name (const gchar *prefix);38gchar *fio_unique_name (const gchar *prefix);
3739
38#endif /* _FIO_H_ */40G_END_DECLS
41
42#endif /* __FIO_H__ */
3943
=== modified file 'src/help.c'
--- src/help.c 2014-06-21 11:03:38 +0000
+++ src/help.c 2014-09-08 13:22:52 +0000
@@ -20,10 +20,12 @@
20*/20*/
2121
22#include "../config.h"22#include "../config.h"
23
23#include "help.h"24#include "help.h"
25#include "xpad-app.h"
24#include <gtk/gtk.h>26#include <gtk/gtk.h>
25#include <glib/gi18n.h>27#include <glib/gi18n.h>
26#include "xpad-app.h"28
2729
28GtkWindow *help_window = NULL;30GtkWindow *help_window = NULL;
2931
3032
=== modified file 'src/help.h'
--- src/help.h 2014-06-10 20:55:56 +0000
+++ src/help.h 2014-09-08 13:22:52 +0000
@@ -19,9 +19,9 @@
1919
20*/20*/
2121
22#ifndef HELP_H22#ifndef __HELP_H__
23#define HELP_H23#define __HELP_H__
2424
25void show_help (void);25void show_help (void);
2626
27#endif27#endif /* __HELP_H__ */
2828
=== modified file 'src/prefix.h'
--- src/prefix.h 2008-09-21 00:03:40 +0000
+++ src/prefix.h 2014-09-08 13:22:52 +0000
@@ -26,8 +26,8 @@
26 * to br_*", try renaming prefix.c to prefix.cpp26 * to br_*", try renaming prefix.c to prefix.cpp
27 */27 */
2828
29#ifndef _PREFIX_H_29#ifndef __PREFIX_H__
30#define _PREFIX_H_30#define __PREFIX_H__
3131
32#ifdef __cplusplus32#ifdef __cplusplus
33extern "C" {33extern "C" {
@@ -126,4 +126,4 @@
126}126}
127#endif /* __cplusplus */127#endif /* __cplusplus */
128128
129#endif /* _PREFIX_H_ */129#endif /* __PREFIX_H__ */
130130
=== modified file 'src/xpad-app.c'
--- src/xpad-app.c 2014-07-23 10:03:02 +0000
+++ src/xpad-app.c 2014-09-08 13:22:52 +0000
@@ -25,15 +25,8 @@
25 Unfortunately, we lose portability... */25 Unfortunately, we lose portability... */
2626
27#include "../config.h"27#include "../config.h"
28
28#include "xpad-app.h"29#include "xpad-app.h"
29#include <glib.h>
30#include <glib/gi18n.h>
31#include <glib/gstdio.h>
32#include <string.h>
33#include <sys/socket.h>
34#include <sys/un.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include "help.h"30#include "help.h"
38#include "xpad-pad.h"31#include "xpad-pad.h"
39#include "xpad-pad-group.h"32#include "xpad-pad-group.h"
@@ -41,6 +34,16 @@
41#include "xpad-session-manager.h"34#include "xpad-session-manager.h"
42#include "xpad-tray.h"35#include "xpad-tray.h"
4336
37#include <string.h>
38#include <sys/socket.h>
39#include <sys/un.h>
40#include <stdio.h>
41#include <stdlib.h>
42
43#include <glib.h>
44#include <glib/gi18n.h>
45#include <glib/gstdio.h>
46
44/* Seems that some systems (sun-sparc-solaris2.8 at least), need the following three #defines. 47/* Seems that some systems (sun-sparc-solaris2.8 at least), need the following three #defines.
45 These were provided by Alan Mizrahi <alan@cesma.usb.ve>.48 These were provided by Alan Mizrahi <alan@cesma.usb.ve>.
46*/49*/
@@ -76,137 +79,36 @@
76static gint pads_loaded_on_start = 0;79static gint pads_loaded_on_start = 0;
77static XpadSettings *settings;80static XpadSettings *settings;
7881
79static gboolean process_local_args (gint *argc, gchar **argv[]);82/**
80static gboolean process_remote_args (gint *argc, gchar **argv[], gboolean have_gtk, XpadSettings *xpad_settings);83 * Here are the functions called when arguments are passed to us.
8184 */
82static gboolean config_dir_exists (void);85
83static gchar *make_config_dir (void);86static GOptionEntry local_options[] =
84static void register_stock_icons (void);87{
85static gint xpad_app_load_pads (void);88 {"version", 'v', 0, G_OPTION_ARG_NONE, &option_version, N_("Show version number and quit"), NULL},
86static gboolean xpad_app_quit_if_no_pads (XpadPadGroup *group);89 {"no-new", 'N', 0, G_OPTION_ARG_NONE, &option_nonew, N_("Don't create a new pad on startup if no previous pads exist"), NULL},
87static gboolean xpad_app_first_idle_check (XpadPadGroup *group);90 {NULL}
88static gboolean xpad_app_pass_args (void);91};
89static gboolean xpad_app_open_proc_file (void);92
9093static GOptionEntry remote_options[] =
91static void94{
92xpad_app_init (int argc, char **argv)95 {"new", 'n', 0, G_OPTION_ARG_NONE, &option_new, N_("Create a new pad on startup even if pads already exist"), NULL},
93{96 {"hide", 'h', 0, G_OPTION_ARG_NONE, &option_hide, N_("Hide all pads"), NULL},
94 gboolean first_time;97 {"show", 's', 0, G_OPTION_ARG_NONE, &option_show, N_("Show all pads"), NULL},
95 gboolean have_gtk;98 {"toggle", 't', 0, G_OPTION_ARG_NONE, &option_toggle, N_("Toggle between show and hide all pads"), NULL},
9699 {"new-from-file", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &option_files, N_("Create a new pad with the contents of a file"), N_("FILE")},
97 /* Set up support different languages */100 {"quit", 'q', 0, G_OPTION_ARG_NONE, &option_quit, N_("Close all pads"), NULL},
98#ifdef ENABLE_NLS101 {"sm-client-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &option_smid, NULL, NULL},
99 bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);102 {NULL}
100 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");103};
101 textdomain (GETTEXT_PACKAGE);
102#endif
103
104 have_gtk = gtk_init_check (&argc, &argv);
105 xpad_argc = argc;
106 xpad_argv = argv;
107 output = stdout;
108
109 /* Set up config directory. */
110 first_time = !config_dir_exists ();
111 config_dir = make_config_dir ();
112
113 /* create master socket name */
114 server_filename = g_build_filename (xpad_app_get_config_dir (), "server", NULL);
115
116 if (!have_gtk)
117 {
118 /* We don't have GTK+, but we can still do
119 --version or --help and such. Plus, we
120 can pass commands to a remote instance. */
121 process_local_args (&xpad_argc, &xpad_argv);
122 if (!xpad_app_pass_args ())
123 {
124 process_remote_args (&xpad_argc, &xpad_argv, FALSE, settings);
125 fprintf (output, "%s\n", _("Xpad is a graphical program. Please run it from your desktop."));
126 }
127 exit (0);
128 }
129
130 g_set_application_name (_("Xpad"));
131 gdk_set_program_class (PACKAGE);
132
133 /* Set up program path. */
134 if (xpad_argc > 0)
135 program_path = g_find_program_in_path (xpad_argv[0]);
136 else
137 program_path = NULL;
138
139 process_local_args (&xpad_argc, &xpad_argv);
140
141 if (xpad_app_pass_args ())
142 exit (0);
143
144 /* Race condition here, between calls */
145 xpad_app_open_proc_file ();
146
147 register_stock_icons ();
148 gtk_window_set_default_icon_name (PACKAGE);
149
150 /* Read the Xpad configuration file from disk (if exists) */
151 settings = xpad_settings_new ();
152
153 /* Delay program startup, if user configured it, to wait for example for the loading of the systray. */
154 guint autostart_delay;
155 g_object_get (settings, "autostart-delay", &autostart_delay, NULL);
156
157 if (autostart_delay)
158 sleep(autostart_delay);
159
160 pad_group = xpad_pad_group_new();
161 process_remote_args (&xpad_argc, &xpad_argv, TRUE, settings);
162
163 xpad_tray_init (settings);
164 xpad_session_manager_init ();
165
166 /* Initialize Xpad-periodic module */
167 xpad_periodic_init ();
168 xpad_periodic_set_callback ("save-content", (XpadPeriodicFunc) xpad_pad_save_content);
169 xpad_periodic_set_callback ("save-info", (XpadPeriodicFunc) xpad_pad_save_info);
170
171 /* load all pads */
172 pads_loaded_on_start = xpad_app_load_pads ();
173 if (pads_loaded_on_start == 0 && !option_new) {
174 if (!option_nonew) {
175 GtkWidget *pad = xpad_pad_new (pad_group, settings);
176 gtk_widget_show (pad);
177 }
178 }
179
180 /* Since all pads have been loaded, reprocess the show/hide/toggle option for all pads */
181 if (have_gtk && (option_show))
182 xpad_pad_group_show_all (pad_group);
183 if (have_gtk && (option_hide))
184 xpad_pad_group_close_all (pad_group);
185 if (have_gtk && option_toggle)
186 xpad_pad_group_toggle_hide (pad_group);
187
188 g_idle_add ((GSourceFunc)xpad_app_first_idle_check, pad_group);
189
190 if (first_time)
191 show_help ();
192
193 g_free (server_filename);
194 server_filename = NULL;
195}
196
197gint main (gint argc, gchar **argv)
198{ xpad_app_init (argc, argv);
199
200 gtk_main ();
201
202 return 0;
203}
204104
205/* parent and secondary may be NULL.105/* parent and secondary may be NULL.
206 * Returns when user dismisses error.106 * Returns when user dismisses error.
207 */107 */
208void108void
209xpad_app_error (GtkWindow *parent, const gchar *primary, const gchar *secondary)109xpad_app_error (GtkWindow *parent,
110 const gchar *primary,
111 const gchar *secondary)
210{112{
211 GtkWidget *dialog;113 GtkWidget *dialog;
212 114
@@ -215,7 +117,7 @@
215 117
216 g_printerr ("%s\n", primary);118 g_printerr ("%s\n", primary);
217 119
218 dialog = xpad_app_alert_dialog (parent, "dialog-error", primary, secondary); 120 dialog = xpad_app_alert_dialog (parent, "dialog-error", primary, secondary);
219 gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Ok"), GTK_RESPONSE_OK, NULL);121 gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Ok"), GTK_RESPONSE_OK, NULL);
220 gtk_dialog_run (GTK_DIALOG (dialog));122 gtk_dialog_run (GTK_DIALOG (dialog));
221 gtk_widget_destroy (dialog);123 gtk_widget_destroy (dialog);
@@ -349,7 +251,10 @@
349 * secondary text of 'secondary'. No buttons are added.251 * secondary text of 'secondary'. No buttons are added.
350 */252 */
351GtkWidget *253GtkWidget *
352xpad_app_alert_dialog (GtkWindow *parent, const gchar *icon_name, const gchar *primary, const gchar *secondary)254xpad_app_alert_dialog (GtkWindow *parent,
255 const gchar *icon_name,
256 const gchar *primary,
257 const gchar *secondary)
353{258{
354 GtkWidget *dialog, *hbox, *image, *label;259 GtkWidget *dialog, *hbox, *image, *label;
355 gchar *buf;260 gchar *buf;
@@ -360,7 +265,7 @@
360 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);265 gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
361266
362 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);267 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
363 image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DIALOG); 268 image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DIALOG);
364 label = gtk_label_new (NULL);269 label = gtk_label_new (NULL);
365 270
366 if (secondary)271 if (secondary)
@@ -440,13 +345,13 @@
440}345}
441346
442static void347static void
443xpad_app_pad_added (XpadPadGroup *group, XpadPad *pad)348xpad_app_pad_added (XpadPadGroup *group,
349 XpadPad *pad)
444{350{
445 g_signal_connect_swapped (pad, "closed", G_CALLBACK (xpad_app_quit_if_no_pads), group);351 g_signal_connect_swapped (pad, "closed", G_CALLBACK (xpad_app_quit_if_no_pads), group);
446 g_signal_connect_swapped (pad, "destroy", G_CALLBACK (xpad_app_quit_if_no_pads), group);352 g_signal_connect_swapped (pad, "destroy", G_CALLBACK (xpad_app_quit_if_no_pads), group);
447}353}
448354
449
450/* Scans config directory for pad files and loads them. */355/* Scans config directory for pad files and loads them. */
451static gint356static gint
452xpad_app_load_pads (void)357xpad_app_load_pads (void)
@@ -499,7 +404,9 @@
499puts allocated string in dest, and returns size404puts allocated string in dest, and returns size
500*/405*/
501static guint406static guint
502args_to_string (int argc, char **argv, char **dest)407args_to_string (int argc,
408 char **argv,
409 char **dest)
503{410{
504 gint i = 0;411 gint i = 0;
505 guint size = 0;412 guint size = 0;
@@ -541,7 +448,8 @@
541returns number of strings in newly allocated argv448returns number of strings in newly allocated argv
542*/449*/
543static guint450static guint
544string_to_args (const char *string, char ***argv)451string_to_args (const char *string,
452 char ***argv)
545{453{
546 guint num, i;454 guint num, i;
547 const gchar *tmp;455 const gchar *tmp;
@@ -589,6 +497,82 @@
589 return num;497 return num;
590}498}
591499
500static gboolean
501process_remote_args (gint *argc,
502 gchar **argv[],
503 gboolean have_gtk,
504 XpadSettings *xpad_settings)
505{
506 GError *error = NULL;
507 GOptionContext *context;
508
509 option_new = FALSE;
510 option_files = NULL;
511 option_quit = FALSE;
512 option_smid = NULL;
513 option_hide = FALSE;
514 option_show = FALSE;
515 option_toggle = FALSE;
516
517 context = g_option_context_new (NULL);
518 g_option_context_set_ignore_unknown_options (context, TRUE);
519 g_option_context_set_help_enabled (context, FALSE);
520 g_option_context_add_main_entries (context, remote_options, GETTEXT_PACKAGE);
521 if (g_option_context_parse (context, argc, argv, &error))
522 {
523 if (have_gtk && option_smid)
524 xpad_session_manager_set_id (option_smid);
525
526 if (!option_new)
527 g_object_get (settings, "autostart-new-pad", &option_new, NULL);
528
529 if (have_gtk && option_new)
530 {
531 GtkWidget *pad = xpad_pad_new (pad_group, settings);
532 gtk_widget_show (pad);
533 }
534
535 if (!option_hide && !option_show) {
536 guint display_pads;
537 g_object_get (xpad_settings, "autostart-display-pads", &display_pads, NULL);
538 if (display_pads == 0)
539 option_show = TRUE;
540 else if (display_pads == 1)
541 option_hide = TRUE;
542 }
543
544 if (have_gtk && option_files)
545 {
546 int i;
547 for (i = 0; option_files[i]; i++)
548 {
549 GtkWidget *pad = xpad_pad_new_from_file (pad_group, settings, option_files[i]);
550 if (pad)
551 gtk_widget_show (pad);
552 }
553 }
554
555 if (option_quit)
556 {
557 if (have_gtk && gtk_main_level () > 0)
558 xpad_app_quit ();
559 else
560 exit (0);
561 }
562 }
563 else
564 {
565 fprintf (output, "%s\n", error->message);
566 /* Don't quit. Bad options passed to the main xpad program by other
567 iterations shouldn't close the main one. */
568 }
569
570 g_option_context_free (context);
571
572 return(option_new || option_quit || option_smid || option_files ||
573 option_hide || option_show || option_toggle);
574}
575
592/* This reads a line from the proc file. This line will contain arguments to process. */576/* This reads a line from the proc file. This line will contain arguments to process. */
593static void577static void
594xpad_app_read_from_proc_file (void)578xpad_app_read_from_proc_file (void)
@@ -661,7 +645,9 @@
661}645}
662646
663static gboolean647static gboolean
664can_read_from_server_fd (GIOChannel *source, GIOCondition condition, gpointer data)648can_read_from_server_fd (GIOChannel *source,
649 GIOCondition condition,
650 gpointer data)
665{651{
666 /* A dirty way to silence the compiler for these unused variables. */652 /* A dirty way to silence the compiler for these unused variables. */
667 (void) source;653 (void) source;
@@ -702,7 +688,6 @@
702 return TRUE;688 return TRUE;
703}689}
704690
705
706static gboolean691static gboolean
707xpad_app_pass_args (void)692xpad_app_pass_args (void)
708{693{
@@ -770,31 +755,9 @@
770 return connected;755 return connected;
771}756}
772757
773/**
774 * Here are the functions called when arguments are passed to us.
775 */
776
777static GOptionEntry local_options[] =
778{
779 {"version", 'v', 0, G_OPTION_ARG_NONE, &option_version, N_("Show version number and quit"), NULL},
780 {"no-new", 'N', 0, G_OPTION_ARG_NONE, &option_nonew, N_("Don't create a new pad on startup if no previous pads exist"), NULL},
781 {NULL}
782};
783
784static GOptionEntry remote_options[] =
785{
786 {"new", 'n', 0, G_OPTION_ARG_NONE, &option_new, N_("Create a new pad on startup even if pads already exist"), NULL},
787 {"hide", 'h', 0, G_OPTION_ARG_NONE, &option_hide, N_("Hide all pads"), NULL},
788 {"show", 's', 0, G_OPTION_ARG_NONE, &option_show, N_("Show all pads"), NULL},
789 {"toggle", 't', 0, G_OPTION_ARG_NONE, &option_toggle, N_("Toggle between show and hide all pads"), NULL},
790 {"new-from-file", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &option_files, N_("Create a new pad with the contents of a file"), N_("FILE")},
791 {"quit", 'q', 0, G_OPTION_ARG_NONE, &option_quit, N_("Close all pads"), NULL},
792 {"sm-client-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &option_smid, NULL, NULL},
793 {NULL}
794};
795
796static gboolean758static gboolean
797process_local_args (gint *argc, gchar **argv[])759process_local_args (gint *argc,
760 gchar **argv[])
798{761{
799 GError *error = NULL;762 GError *error = NULL;
800 GOptionContext *context;763 GOptionContext *context;
@@ -836,75 +799,119 @@
836 return (option_version || option_nonew);799 return (option_version || option_nonew);
837}800}
838801
839static gboolean802static void
840process_remote_args (gint *argc, gchar **argv[], gboolean have_gtk, XpadSettings *xpad_settings)803xpad_app_init (int argc,
804 char **argv)
841{805{
842 GError *error = NULL;806 gboolean first_time;
843 GOptionContext *context;807 gboolean have_gtk;
844 808
845 option_new = FALSE;809 /* Set up support different languages */
846 option_files = NULL;810#ifdef ENABLE_NLS
847 option_quit = FALSE;811 bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
848 option_smid = NULL;812 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
849 option_hide = FALSE;813 textdomain (GETTEXT_PACKAGE);
850 option_show = FALSE;814#endif
851 option_toggle = FALSE;815
852 816 have_gtk = gtk_init_check (&argc, &argv);
853 context = g_option_context_new (NULL);817 xpad_argc = argc;
854 g_option_context_set_ignore_unknown_options (context, TRUE);818 xpad_argv = argv;
855 g_option_context_set_help_enabled (context, FALSE);819 output = stdout;
856 g_option_context_add_main_entries (context, remote_options, GETTEXT_PACKAGE);820
857 if (g_option_context_parse (context, argc, argv, &error))821 /* Set up config directory. */
822 first_time = !config_dir_exists ();
823 config_dir = make_config_dir ();
824
825 /* create master socket name */
826 server_filename = g_build_filename (xpad_app_get_config_dir (), "server", NULL);
827
828 if (!have_gtk)
858 {829 {
859 if (have_gtk && option_smid)830 /* We don't have GTK+, but we can still do
860 xpad_session_manager_set_id (option_smid);831 --version or --help and such. Plus, we
861 832 can pass commands to a remote instance. */
862 if (!option_new)833 process_local_args (&xpad_argc, &xpad_argv);
863 g_object_get (settings, "autostart-new-pad", &option_new, NULL);834 if (!xpad_app_pass_args ())
864
865 if (have_gtk && option_new)
866 {835 {
836 process_remote_args (&xpad_argc, &xpad_argv, FALSE, settings);
837 fprintf (output, "%s\n", _("Xpad is a graphical program. Please run it from your desktop."));
838 }
839 exit (0);
840 }
841
842 g_set_application_name (_("Xpad"));
843 gdk_set_program_class (PACKAGE);
844
845 /* Set up program path. */
846 if (xpad_argc > 0)
847 program_path = g_find_program_in_path (xpad_argv[0]);
848 else
849 program_path = NULL;
850
851 process_local_args (&xpad_argc, &xpad_argv);
852
853 if (xpad_app_pass_args ())
854 exit (0);
855
856 /* Race condition here, between calls */
857 xpad_app_open_proc_file ();
858
859 register_stock_icons ();
860 gtk_window_set_default_icon_name (PACKAGE);
861
862 /* Read the Xpad configuration file from disk (if exists) */
863 settings = xpad_settings_new ();
864
865 /* Delay program startup, if user configured it, to wait for example for the loading of the systray. */
866 guint autostart_delay;
867 g_object_get (settings, "autostart-delay", &autostart_delay, NULL);
868
869 if (autostart_delay)
870 sleep(autostart_delay);
871
872 pad_group = xpad_pad_group_new();
873 process_remote_args (&xpad_argc, &xpad_argv, TRUE, settings);
874
875 xpad_tray_init (settings);
876 xpad_session_manager_init ();
877
878 /* Initialize Xpad-periodic module */
879 xpad_periodic_init ();
880 xpad_periodic_set_callback ("save-content", (XpadPeriodicFunc) xpad_pad_save_content);
881 xpad_periodic_set_callback ("save-info", (XpadPeriodicFunc) xpad_pad_save_info);
882
883 /* load all pads */
884 pads_loaded_on_start = xpad_app_load_pads ();
885 if (pads_loaded_on_start == 0 && !option_new) {
886 if (!option_nonew) {
867 GtkWidget *pad = xpad_pad_new (pad_group, settings);887 GtkWidget *pad = xpad_pad_new (pad_group, settings);
868 gtk_widget_show (pad);888 gtk_widget_show (pad);
869 }889 }
870 890 }
871 if (!option_hide && !option_show) {891
872 guint display_pads;892 /* Since all pads have been loaded, reprocess the show/hide/toggle option for all pads */
873 g_object_get (xpad_settings, "autostart-display-pads", &display_pads, NULL);893 if (have_gtk && (option_show))
874 if (display_pads == 0)894 xpad_pad_group_show_all (pad_group);
875 option_show = TRUE;895 if (have_gtk && (option_hide))
876 else if (display_pads == 1)896 xpad_pad_group_close_all (pad_group);
877 option_hide = TRUE;897 if (have_gtk && option_toggle)
878 }898 xpad_pad_group_toggle_hide (pad_group);
879899
880 if (have_gtk && option_files)900 g_idle_add ((GSourceFunc)xpad_app_first_idle_check, pad_group);
881 {901
882 int i;902 if (first_time)
883 for (i = 0; option_files[i]; i++)903 show_help ();
884 {904
885 GtkWidget *pad = xpad_pad_new_from_file (pad_group, settings, option_files[i]);905 g_free (server_filename);
886 if (pad)906 server_filename = NULL;
887 gtk_widget_show (pad);907}
888 }908
889 }909gint main (gint argc,
890 910 gchar **argv)
891 if (option_quit)911{
892 {912 xpad_app_init (argc, argv);
893 if (have_gtk && gtk_main_level () > 0)913
894 xpad_app_quit ();914 gtk_main ();
895 else915
896 exit (0);916 return 0;
897 }
898 }
899 else
900 {
901 fprintf (output, "%s\n", error->message);
902 /* Don't quit. Bad options passed to the main xpad program by other
903 iterations shouldn't close the main one. */
904 }
905
906 g_option_context_free (context);
907
908 return(option_new || option_quit || option_smid || option_files ||
909 option_hide || option_show || option_toggle);
910}917}
911918
=== modified file 'src/xpad-grip-tool-item.c'
--- src/xpad-grip-tool-item.c 2014-06-17 18:22:49 +0000
+++ src/xpad-grip-tool-item.c 2014-09-08 13:22:52 +0000
@@ -20,6 +20,7 @@
20*/20*/
2121
22#include "../config.h"22#include "../config.h"
23
23#include "xpad-grip-tool-item.h"24#include "xpad-grip-tool-item.h"
2425
25struct XpadGripToolItemPrivate26struct XpadGripToolItemPrivate
@@ -29,45 +30,9 @@
2930
30G_DEFINE_TYPE_WITH_PRIVATE(XpadGripToolItem, xpad_grip_tool_item, GTK_TYPE_TOOL_ITEM)31G_DEFINE_TYPE_WITH_PRIVATE(XpadGripToolItem, xpad_grip_tool_item, GTK_TYPE_TOOL_ITEM)
3132
32static gboolean xpad_grip_tool_item_event_box_draw (GtkWidget *widget, cairo_t *cr);
33static void xpad_grip_tool_item_event_box_realize (GtkWidget *widget);
34static gboolean xpad_grip_tool_item_button_pressed_event (GtkWidget *widget, GdkEventButton *event);
35
36GtkToolItem *
37xpad_grip_tool_item_new (void)
38{
39 return GTK_TOOL_ITEM (g_object_new (XPAD_TYPE_GRIP_TOOL_ITEM, NULL));
40}
41
42static void
43xpad_grip_tool_item_class_init (XpadGripToolItemClass *klass)
44{
45}
46
47static void
48xpad_grip_tool_item_init (XpadGripToolItem *grip)
49{
50 GtkWidget *alignment;
51 gboolean right;
52
53 grip->priv = xpad_grip_tool_item_get_instance_private(grip);
54
55 grip->priv->drawbox = gtk_drawing_area_new ();
56 gtk_widget_add_events (grip->priv->drawbox, GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE_MASK);
57 g_signal_connect (grip->priv->drawbox, "button-press-event", G_CALLBACK (xpad_grip_tool_item_button_pressed_event), NULL);
58 g_signal_connect (grip->priv->drawbox, "realize", G_CALLBACK (xpad_grip_tool_item_event_box_realize), NULL);
59 g_signal_connect (grip->priv->drawbox, "draw", G_CALLBACK (xpad_grip_tool_item_event_box_draw), NULL);
60 gtk_widget_set_size_request (grip->priv->drawbox, 18, 18);
61
62 right = gtk_widget_get_direction (grip->priv->drawbox) == GTK_TEXT_DIR_LTR;
63 alignment = gtk_alignment_new (right ? 1 : 0, 1, 0, 0);
64
65 gtk_container_add (GTK_CONTAINER (alignment), grip->priv->drawbox);
66 gtk_container_add (GTK_CONTAINER (grip), alignment);
67}
68
69static gboolean33static gboolean
70xpad_grip_tool_item_button_pressed_event (GtkWidget *widget, GdkEventButton *event)34xpad_grip_tool_item_button_pressed_event (GtkWidget *widget,
35 GdkEventButton *event)
71{36{
72 if (event->button == 1)37 if (event->button == 1)
73 {38 {
@@ -105,7 +70,8 @@
105}70}
10671
107static gboolean72static gboolean
108xpad_grip_tool_item_event_box_draw (GtkWidget *widget, cairo_t *cr)73xpad_grip_tool_item_event_box_draw (GtkWidget *widget,
74 cairo_t *cr)
109{75{
110 gtk_render_handle(gtk_widget_get_style_context(widget),76 gtk_render_handle(gtk_widget_get_style_context(widget),
111 cr,77 cr,
@@ -115,3 +81,36 @@
115 81
116 return FALSE;82 return FALSE;
117}83}
84
85static void
86xpad_grip_tool_item_class_init (XpadGripToolItemClass *klass)
87{
88}
89
90static void
91xpad_grip_tool_item_init (XpadGripToolItem *grip)
92{
93 GtkWidget *alignment;
94 gboolean right;
95
96 grip->priv = xpad_grip_tool_item_get_instance_private(grip);
97
98 grip->priv->drawbox = gtk_drawing_area_new ();
99 gtk_widget_add_events (grip->priv->drawbox, GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE_MASK);
100 g_signal_connect (grip->priv->drawbox, "button-press-event", G_CALLBACK (xpad_grip_tool_item_button_pressed_event), NULL);
101 g_signal_connect (grip->priv->drawbox, "realize", G_CALLBACK (xpad_grip_tool_item_event_box_realize), NULL);
102 g_signal_connect (grip->priv->drawbox, "draw", G_CALLBACK (xpad_grip_tool_item_event_box_draw), NULL);
103 gtk_widget_set_size_request (grip->priv->drawbox, 18, 18);
104
105 right = gtk_widget_get_direction (grip->priv->drawbox) == GTK_TEXT_DIR_LTR;
106 alignment = gtk_alignment_new (right ? 1 : 0, 1, 0, 0);
107
108 gtk_container_add (GTK_CONTAINER (alignment), grip->priv->drawbox);
109 gtk_container_add (GTK_CONTAINER (grip), alignment);
110}
111
112GtkToolItem *
113xpad_grip_tool_item_new (void)
114{
115 return GTK_TOOL_ITEM (g_object_new (XPAD_TYPE_GRIP_TOOL_ITEM, NULL));
116}
118117
=== modified file 'src/xpad-pad-group.c'
--- src/xpad-pad-group.c 2014-07-23 10:03:02 +0000
+++ src/xpad-pad-group.c 2014-09-08 13:22:52 +0000
@@ -21,6 +21,7 @@
21*/21*/
2222
23#include "../config.h"23#include "../config.h"
24
24#include "xpad-pad-group.h"25#include "xpad-pad-group.h"
25#include "xpad-pad.h"26#include "xpad-pad.h"
2627
@@ -31,8 +32,6 @@
3132
32G_DEFINE_TYPE_WITH_PRIVATE (XpadPadGroup, xpad_pad_group, G_TYPE_OBJECT)33G_DEFINE_TYPE_WITH_PRIVATE (XpadPadGroup, xpad_pad_group, G_TYPE_OBJECT)
3334
34static void xpad_pad_group_save_unsaved_all (XpadPadGroup *group);
35
36enum {35enum {
37 PROP_036 PROP_0
38};37};
@@ -75,7 +74,7 @@
75 G_TYPE_NONE,74 G_TYPE_NONE,
76 1,75 1,
77 GTK_TYPE_WIDGET);76 GTK_TYPE_WIDGET);
78 77
79 signals[PAD_REMOVED] =78 signals[PAD_REMOVED] =
80 g_signal_new ("pad_removed",79 g_signal_new ("pad_removed",
81 G_OBJECT_CLASS_TYPE (object_class),80 G_OBJECT_CLASS_TYPE (object_class),
@@ -96,10 +95,11 @@
9695
97/* Add a pad to this group */96/* Add a pad to this group */
98void97void
99xpad_pad_group_add (XpadPadGroup *group, GtkWidget *pad)98xpad_pad_group_add (XpadPadGroup *group,
99 GtkWidget *pad)
100{100{
101 g_object_ref(pad);101 g_object_ref(pad);
102 102
103 group->priv->pads = g_slist_append (group->priv->pads, XPAD_PAD (pad));103 group->priv->pads = g_slist_append (group->priv->pads, XPAD_PAD (pad));
104 g_signal_connect_swapped (pad, "destroy", G_CALLBACK (xpad_pad_group_remove), group);104 g_signal_connect_swapped (pad, "destroy", G_CALLBACK (xpad_pad_group_remove), group);
105 105
@@ -108,7 +108,8 @@
108108
109/* Remove a pad from this group */109/* Remove a pad from this group */
110void110void
111xpad_pad_group_remove (XpadPadGroup *group, GtkWidget *pad)111xpad_pad_group_remove (XpadPadGroup *group,
112 GtkWidget *pad)
112{113{
113 group->priv->pads = g_slist_remove (group->priv->pads, XPAD_PAD (pad));114 group->priv->pads = g_slist_remove (group->priv->pads, XPAD_PAD (pad));
114 g_object_unref(pad);115 g_object_unref(pad);
@@ -117,6 +118,13 @@
117 g_signal_emit (group, signals[PAD_REMOVED], 0, pad);118 g_signal_emit (group, signals[PAD_REMOVED], 0, pad);
118}119}
119120
121static void
122xpad_pad_group_save_unsaved_all (XpadPadGroup *group)
123{
124 if (group)
125 g_slist_foreach (group->priv->pads, (GFunc) xpad_pad_save_unsaved, NULL);
126}
127
120/* Delete all the current pads in the group */128/* Delete all the current pads in the group */
121void129void
122xpad_pad_group_destroy_pads (XpadPadGroup *group)130xpad_pad_group_destroy_pads (XpadPadGroup *group)
@@ -146,14 +154,10 @@
146 }154 }
147 g_slist_free(i);155 g_slist_free(i);
148 }156 }
157
149 return num;158 return num;
150}159}
151160
152static void xpad_pad_group_save_unsaved_all (XpadPadGroup *group) {
153 if (group)
154 g_slist_foreach (group->priv->pads, (GFunc) xpad_pad_save_unsaved, NULL);
155}
156
157void161void
158xpad_pad_group_close_all (XpadPadGroup *group)162xpad_pad_group_close_all (XpadPadGroup *group)
159{163{
160164
=== modified file 'src/xpad-pad-properties.c'
--- src/xpad-pad-properties.c 2014-06-19 12:35:19 +0000
+++ src/xpad-pad-properties.c 2014-09-08 13:22:52 +0000
@@ -21,44 +21,35 @@
2121
22#include "../config.h"22#include "../config.h"
23#include "xpad-pad-properties.h"23#include "xpad-pad-properties.h"
24#include <gtk/gtk.h>
24#include <glib/gi18n.h>25#include <glib/gi18n.h>
25#include <gtk/gtk.h>
2626
27struct XpadPadPropertiesPrivate 27struct XpadPadPropertiesPrivate
28{28{
29 GtkWidget *fontcheck;29 GtkWidget *fontcheck;
30 GtkWidget *colorcheck;30 GtkWidget *colorcheck;
31 GtkWidget *colorbox;31 GtkWidget *colorbox;
32 32
33 GtkWidget *textbutton;33 GtkWidget *textbutton;
34 GdkRGBA texttmp;34 GdkRGBA texttmp;
35 35
36 GtkWidget *backbutton;36 GtkWidget *backbutton;
37 GdkRGBA backtmp;37 GdkRGBA backtmp;
38 38
39 GtkWidget *fontbutton;39 GtkWidget *fontbutton;
40};40};
4141
42G_DEFINE_TYPE_WITH_PRIVATE (XpadPadProperties, xpad_pad_properties, GTK_TYPE_DIALOG)42G_DEFINE_TYPE_WITH_PRIVATE (XpadPadProperties, xpad_pad_properties, GTK_TYPE_DIALOG)
4343
44static void xpad_pad_properties_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
45static void xpad_pad_properties_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
46static void xpad_pad_properties_response (GtkDialog *dialog, gint response);
47static void change_color_check (GtkToggleButton *button, XpadPadProperties *prop);
48static void change_font_check (GtkToggleButton *button, XpadPadProperties *prop);
49static void change_text_color (XpadPadProperties *prop);
50static void change_back_color (XpadPadProperties *prop);
51static void change_font_face (XpadPadProperties *prop);
52
53enum44enum
54{45{
55 PROP_0,46 PROP_0,
56 PROP_FOLLOW_FONT_STYLE,47 PROP_FOLLOW_FONT_STYLE,
57 PROP_FOLLOW_COLOR_STYLE,48 PROP_FOLLOW_COLOR_STYLE,
58 PROP_BACK_COLOR,49 PROP_BACK_COLOR,
59 PROP_TEXT_COLOR,50 PROP_TEXT_COLOR,
60 PROP_FONTNAME,51 PROP_FONTNAME,
61 N_PROPERTIES52 N_PROPERTIES
62};53};
6354
64static GParamSpec *obj_prop[N_PROPERTIES] = { NULL, };55static GParamSpec *obj_prop[N_PROPERTIES] = { NULL, };
@@ -69,6 +60,125 @@
69 return g_object_new (XPAD_TYPE_PAD_PROPERTIES, NULL);60 return g_object_new (XPAD_TYPE_PAD_PROPERTIES, NULL);
70}61}
7162
63
64static void
65xpad_pad_properties_response (GtkDialog *dialog,
66 gint response)
67{
68 if (response == GTK_RESPONSE_CLOSE)
69 gtk_widget_destroy (GTK_WIDGET (dialog));
70}
71
72static void
73change_font_check (GtkToggleButton *button,
74 XpadPadProperties *prop)
75{
76 gtk_widget_set_sensitive (prop->priv->fontbutton, gtk_toggle_button_get_active (button));
77
78 g_object_notify (G_OBJECT (prop), "follow-font-style");
79}
80
81static void
82change_color_check (GtkToggleButton *button,
83 XpadPadProperties *prop)
84{
85 gtk_widget_set_sensitive (prop->priv->colorbox, gtk_toggle_button_get_active (button));
86
87 g_object_notify (G_OBJECT (prop), "follow-color-style");
88}
89
90static void
91change_text_color (XpadPadProperties *prop)
92{
93 g_object_notify (G_OBJECT (prop), "text-color");
94}
95
96static void
97change_back_color (XpadPadProperties *prop)
98{
99 g_object_notify (G_OBJECT (prop), "back-color");
100}
101
102static void
103change_font_face (XpadPadProperties *prop)
104{
105 g_object_notify (G_OBJECT (prop), "fontname");
106}
107
108static void
109xpad_pad_properties_set_property (GObject *object,
110 guint prop_id,
111 const GValue *value,
112 GParamSpec *pspec)
113{
114 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (object);
115
116 switch (prop_id)
117 {
118 case PROP_FOLLOW_FONT_STYLE:
119 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prop->priv->fontcheck), !g_value_get_boolean (value));
120 break;
121
122 case PROP_FOLLOW_COLOR_STYLE:
123 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prop->priv->colorcheck), !g_value_get_boolean (value));
124 break;
125
126 case PROP_BACK_COLOR:
127 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (prop->priv->backbutton), g_value_get_boxed (value));
128 break;
129
130 case PROP_TEXT_COLOR:
131 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (prop->priv->textbutton), g_value_get_boxed (value));
132 break;
133
134 case PROP_FONTNAME:
135 gtk_font_button_set_font_name (GTK_FONT_BUTTON (prop->priv->fontbutton), g_value_get_string (value));
136 break;
137
138 default:
139 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
140 break;
141 }
142}
143
144static void
145xpad_pad_properties_get_property (GObject *object,
146 guint prop_id,
147 GValue *value,
148 GParamSpec *pspec)
149{
150 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (object);
151
152 switch (prop_id)
153 {
154 case PROP_FOLLOW_FONT_STYLE:
155 g_value_set_boolean (value, !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prop->priv->fontcheck)));
156 break;
157
158 case PROP_FOLLOW_COLOR_STYLE:
159 g_value_set_boolean (value, !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prop->priv->colorcheck)));
160 break;
161
162 case PROP_BACK_COLOR:
163 gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (prop->priv->backbutton), &prop->priv->backtmp);
164 g_value_set_static_boxed (value, &prop->priv->backtmp);
165 break;
166
167 case PROP_TEXT_COLOR:
168 gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (prop->priv->textbutton), &prop->priv->texttmp);
169 g_value_set_static_boxed (value, &prop->priv->texttmp);
170 break;
171
172 case PROP_FONTNAME:
173 g_value_set_string (value, gtk_font_button_get_font_name (GTK_FONT_BUTTON (prop->priv->fontbutton)));
174 break;
175
176 default:
177 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
178 break;
179 }
180}
181
72static void182static void
73xpad_pad_properties_class_init (XpadPadPropertiesClass *klass)183xpad_pad_properties_class_init (XpadPadPropertiesClass *klass)
74{184{
@@ -93,9 +203,9 @@
93 GtkBox *hbox, *font_hbox, *vbox, *appearance_vbox;203 GtkBox *hbox, *font_hbox, *vbox, *appearance_vbox;
94 GtkWidget *font_radio, *color_radio, *label, *appearance_frame, *alignment;204 GtkWidget *font_radio, *color_radio, *label, *appearance_frame, *alignment;
95 GtkSizeGroup *size_group_labels = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);205 GtkSizeGroup *size_group_labels = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
96 206
97 prop->priv = xpad_pad_properties_get_instance_private (prop);207 prop->priv = xpad_pad_properties_get_instance_private (prop);
98 208
99 text = g_strconcat ("<b>", _("Appearance"), "</b>", NULL);209 text = g_strconcat ("<b>", _("Appearance"), "</b>", NULL);
100 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,210 label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
101 "label", text,211 "label", text,
@@ -119,7 +229,7 @@
119 "child", alignment,229 "child", alignment,
120 "border-width", 6,230 "border-width", 6,
121 NULL));231 NULL));
122 232
123 prop->priv->fontbutton = gtk_font_button_new ();233 prop->priv->fontbutton = gtk_font_button_new ();
124 prop->priv->textbutton = gtk_color_button_new ();234 prop->priv->textbutton = gtk_color_button_new ();
125 prop->priv->backbutton = gtk_color_button_new ();235 prop->priv->backbutton = gtk_color_button_new ();
@@ -133,7 +243,7 @@
133243
134 gtk_box_pack_start (font_hbox, prop->priv->fontcheck, FALSE, FALSE, 0);244 gtk_box_pack_start (font_hbox, prop->priv->fontcheck, FALSE, FALSE, 0);
135 gtk_box_pack_start (font_hbox, prop->priv->fontbutton, TRUE, TRUE, 0);245 gtk_box_pack_start (font_hbox, prop->priv->fontbutton, TRUE, TRUE, 0);
136 246
137 prop->priv->colorbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);247 prop->priv->colorbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
138248
139 hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12));249 hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12));
@@ -143,7 +253,7 @@
143 gtk_box_pack_start (hbox, label, FALSE, FALSE, 0);253 gtk_box_pack_start (hbox, label, FALSE, FALSE, 0);
144 gtk_box_pack_start (hbox, prop->priv->textbutton, TRUE, TRUE, 0);254 gtk_box_pack_start (hbox, prop->priv->textbutton, TRUE, TRUE, 0);
145 g_object_set (G_OBJECT (prop->priv->colorbox), "child", hbox, NULL);255 g_object_set (G_OBJECT (prop->priv->colorbox), "child", hbox, NULL);
146 256
147 hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12));257 hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12));
148 label = gtk_label_new_with_mnemonic (_("Background:"));258 label = gtk_label_new_with_mnemonic (_("Background:"));
149 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);259 gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
@@ -151,22 +261,22 @@
151 gtk_box_pack_start (hbox, label, FALSE, FALSE, 0);261 gtk_box_pack_start (hbox, label, FALSE, FALSE, 0);
152 gtk_box_pack_start (hbox, prop->priv->backbutton, TRUE, TRUE, 0);262 gtk_box_pack_start (hbox, prop->priv->backbutton, TRUE, TRUE, 0);
153 g_object_set (G_OBJECT (prop->priv->colorbox), "child", hbox, NULL);263 g_object_set (G_OBJECT (prop->priv->colorbox), "child", hbox, NULL);
154 264
155 alignment = gtk_alignment_new (1, 1, 1, 1);265 alignment = gtk_alignment_new (1, 1, 1, 1);
156 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);266 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
157 gtk_container_add (GTK_CONTAINER (alignment), prop->priv->colorbox);267 gtk_container_add (GTK_CONTAINER (alignment), prop->priv->colorbox);
158 268
159 gtk_dialog_add_button (GTK_DIALOG (prop), "gtk-close", GTK_RESPONSE_CLOSE);269 gtk_dialog_add_button (GTK_DIALOG (prop), "gtk-close", GTK_RESPONSE_CLOSE);
160 gtk_dialog_set_default_response (GTK_DIALOG (prop), GTK_RESPONSE_CLOSE);270 gtk_dialog_set_default_response (GTK_DIALOG (prop), GTK_RESPONSE_CLOSE);
161 g_signal_connect (prop, "response", G_CALLBACK (xpad_pad_properties_response), NULL);271 g_signal_connect (prop, "response", G_CALLBACK (xpad_pad_properties_response), NULL);
162 272
163 gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (prop->priv->textbutton), FALSE);273 gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (prop->priv->textbutton), FALSE);
164 gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (prop->priv->backbutton), TRUE);274 gtk_color_chooser_set_use_alpha (GTK_COLOR_CHOOSER (prop->priv->backbutton), TRUE);
165 275
166 gtk_color_button_set_title (GTK_COLOR_BUTTON (prop->priv->textbutton), _("Set Foreground Color"));276 gtk_color_button_set_title (GTK_COLOR_BUTTON (prop->priv->textbutton), _("Set Foreground Color"));
167 gtk_color_button_set_title (GTK_COLOR_BUTTON (prop->priv->backbutton), _("Set Background Color"));277 gtk_color_button_set_title (GTK_COLOR_BUTTON (prop->priv->backbutton), _("Set Background Color"));
168 gtk_font_button_set_title (GTK_FONT_BUTTON (prop->priv->fontbutton), _("Set Font"));278 gtk_font_button_set_title (GTK_FONT_BUTTON (prop->priv->fontbutton), _("Set Font"));
169 279
170 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));280 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));
171 hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12));281 hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12));
172282
@@ -180,131 +290,22 @@
180 gtk_box_pack_start (vbox, prop->priv->colorcheck, FALSE, FALSE, 0);290 gtk_box_pack_start (vbox, prop->priv->colorcheck, FALSE, FALSE, 0);
181 gtk_box_pack_start (vbox, alignment, FALSE, FALSE, 0);291 gtk_box_pack_start (vbox, alignment, FALSE, FALSE, 0);
182 gtk_box_pack_start (appearance_vbox, GTK_WIDGET (vbox), FALSE, FALSE, 0);292 gtk_box_pack_start (appearance_vbox, GTK_WIDGET (vbox), FALSE, FALSE, 0);
183 293
184 g_signal_connect (prop->priv->fontcheck, "toggled", G_CALLBACK (change_font_check), prop);294 g_signal_connect (prop->priv->fontcheck, "toggled", G_CALLBACK (change_font_check), prop);
185 g_signal_connect (prop->priv->colorcheck, "toggled", G_CALLBACK (change_color_check), prop);295 g_signal_connect (prop->priv->colorcheck, "toggled", G_CALLBACK (change_color_check), prop);
186 g_signal_connect_swapped (prop->priv->fontbutton, "font-set", G_CALLBACK (change_font_face), prop);296 g_signal_connect_swapped (prop->priv->fontbutton, "font-set", G_CALLBACK (change_font_face), prop);
187 g_signal_connect_swapped (prop->priv->textbutton, "color-set", G_CALLBACK (change_text_color), prop);297 g_signal_connect_swapped (prop->priv->textbutton, "color-set", G_CALLBACK (change_text_color), prop);
188 g_signal_connect_swapped (prop->priv->backbutton, "color-set", G_CALLBACK (change_back_color), prop);298 g_signal_connect_swapped (prop->priv->backbutton, "color-set", G_CALLBACK (change_back_color), prop);
189 299
190 /* Setup initial state, which should never be seen, but just in case client doesn't set them itself, we'll be consistent. */300 /* Setup initial state, which should never be seen, but just in case client doesn't set them itself, we'll be consistent. */
191 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (font_radio), TRUE);301 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (font_radio), TRUE);
192 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (color_radio), TRUE);302 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (color_radio), TRUE);
193 gtk_widget_set_sensitive (prop->priv->colorbox, FALSE);303 gtk_widget_set_sensitive (prop->priv->colorbox, FALSE);
194 gtk_widget_set_sensitive (prop->priv->fontbutton, FALSE);304 gtk_widget_set_sensitive (prop->priv->fontbutton, FALSE);
195 305
196 g_object_unref (size_group_labels);306 g_object_unref (size_group_labels);
197 307
198 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (prop))), appearance_frame);308 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (prop))), appearance_frame);
199309
200 gtk_widget_show_all (gtk_dialog_get_content_area (GTK_DIALOG (prop)));310 gtk_widget_show_all (gtk_dialog_get_content_area (GTK_DIALOG (prop)));
201}311}
202
203static void
204xpad_pad_properties_response (GtkDialog *dialog, gint response)
205{
206 if (response == GTK_RESPONSE_CLOSE)
207 gtk_widget_destroy (GTK_WIDGET (dialog));
208}
209
210static void
211change_font_check (GtkToggleButton *button, XpadPadProperties *prop)
212{
213 gtk_widget_set_sensitive (prop->priv->fontbutton, gtk_toggle_button_get_active (button));
214
215 g_object_notify (G_OBJECT (prop), "follow-font-style");
216}
217
218static void
219change_color_check (GtkToggleButton *button, XpadPadProperties *prop)
220{
221 gtk_widget_set_sensitive (prop->priv->colorbox, gtk_toggle_button_get_active (button));
222
223 g_object_notify (G_OBJECT (prop), "follow-color-style");
224}
225
226static void
227change_text_color (XpadPadProperties *prop)
228{
229 g_object_notify (G_OBJECT (prop), "text-color");
230}
231
232static void
233change_back_color (XpadPadProperties *prop)
234{
235 g_object_notify (G_OBJECT (prop), "back-color");
236}
237
238static void
239change_font_face (XpadPadProperties *prop)
240{
241 g_object_notify (G_OBJECT (prop), "fontname");
242}
243
244static void
245xpad_pad_properties_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
246{
247 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (object);
248
249 switch (prop_id)
250 {
251 case PROP_FOLLOW_FONT_STYLE:
252 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prop->priv->fontcheck), !g_value_get_boolean (value));
253 break;
254
255 case PROP_FOLLOW_COLOR_STYLE:
256 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (prop->priv->colorcheck), !g_value_get_boolean (value));
257 break;
258
259 case PROP_BACK_COLOR:
260 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (prop->priv->backbutton), g_value_get_boxed (value));
261 break;
262
263 case PROP_TEXT_COLOR:
264 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (prop->priv->textbutton), g_value_get_boxed (value));
265 break;
266
267 case PROP_FONTNAME:
268 gtk_font_button_set_font_name (GTK_FONT_BUTTON (prop->priv->fontbutton), g_value_get_string (value));
269 break;
270
271 default:
272 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
273 break;
274 }
275}
276
277static void
278xpad_pad_properties_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
279{
280 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (object);
281
282 switch (prop_id)
283 {
284 case PROP_FOLLOW_FONT_STYLE:
285 g_value_set_boolean (value, !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prop->priv->fontcheck)));
286 break;
287
288 case PROP_FOLLOW_COLOR_STYLE:
289 g_value_set_boolean (value, !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (prop->priv->colorcheck)));
290 break;
291
292 case PROP_BACK_COLOR:
293 gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (prop->priv->backbutton), &prop->priv->backtmp);
294 g_value_set_static_boxed (value, &prop->priv->backtmp);
295 break;
296
297 case PROP_TEXT_COLOR:
298 gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (prop->priv->textbutton), &prop->priv->texttmp);
299 g_value_set_static_boxed (value, &prop->priv->texttmp);
300 break;
301
302 case PROP_FONTNAME:
303 g_value_set_string (value, gtk_font_button_get_font_name (GTK_FONT_BUTTON (prop->priv->fontbutton)));
304 break;
305
306 default:
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
308 break;
309 }
310}
311312
=== modified file 'src/xpad-pad.c'
--- src/xpad-pad.c 2014-08-30 18:36:57 +0000
+++ src/xpad-pad.c 2014-09-08 13:22:52 +0000
@@ -24,9 +24,8 @@
24*/24*/
2525
26#include "../config.h"26#include "../config.h"
27
27#include "xpad-pad.h"28#include "xpad-pad.h"
28#include <gtk/gtk.h>
29#include <glib/gi18n.h>
30#include "fio.h"29#include "fio.h"
31#include "help.h"30#include "help.h"
32#include "xpad-app.h"31#include "xpad-app.h"
@@ -38,6 +37,9 @@
38#include "xpad-toolbar.h"37#include "xpad-toolbar.h"
39#include "xpad-tray.h"38#include "xpad-tray.h"
4039
40#include <gtk/gtk.h>
41#include <glib/gi18n.h>
42
41struct XpadPadPrivate43struct XpadPadPrivate
42{44{
43 /* saved values */45 /* saved values */
@@ -97,509 +99,105 @@
97static GParamSpec *obj_prop[N_PROPERTIES] = { NULL, };99static GParamSpec *obj_prop[N_PROPERTIES] = { NULL, };
98static guint signals[LAST_SIGNAL] = { 0 };100static guint signals[LAST_SIGNAL] = { 0 };
99101
100static void xpad_pad_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
101static void xpad_pad_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
102static void xpad_pad_constructed (GObject *object);
103static void xpad_pad_dispose (GObject *object);
104static void xpad_pad_finalize (GObject *object);
105static void xpad_pad_load_info (XpadPad *pad, gboolean *show);
106static GtkWidget *menu_get_popup_highlight (XpadPad *pad, GtkAccelGroup *accel_group);
107static GtkWidget *menu_get_popup_no_highlight (XpadPad *pad, GtkAccelGroup *accel_group);
108static void xpad_pad_show (XpadPad *pad);
109static gboolean xpad_pad_configure_event (XpadPad *pad, GdkEventConfigure *event);
110static gboolean xpad_pad_toolbar_size_allocate (XpadPad *pad, GtkAllocation *event);
111static gboolean xpad_pad_delete_event (XpadPad *pad, GdkEvent *event);
112static gboolean xpad_pad_popup_menu (XpadPad *pad);
113static void menu_popup (XpadPad *pad);
114static void menu_popdown (XpadPad *pad);
115static gboolean xpad_pad_button_press_event (XpadPad *pad, GdkEventButton *event);
116static void xpad_pad_text_changed (XpadPad *pad, GtkTextBuffer *buffer);
117static void xpad_pad_notify_has_scrollbar (XpadPad *pad);
118static void xpad_pad_notify_has_decorations (XpadPad *pad);
119static void xpad_pad_notify_has_toolbar (XpadPad *pad);
120static void xpad_pad_notify_autohide_toolbar (XpadPad *pad);
121static void xpad_pad_hide_toolbar (XpadPad *pad);
122static void xpad_pad_show_toolbar (XpadPad *pad);
123static void xpad_pad_popup (XpadPad *pad, GdkEventButton *event);
124static void xpad_pad_spawn (XpadPad *pad);
125static void xpad_pad_clear (XpadPad *pad);
126static void xpad_pad_undo (XpadPad *pad);
127static void xpad_pad_redo (XpadPad *pad);
128static void xpad_pad_cut (XpadPad *pad);
129static void xpad_pad_copy (XpadPad *pad);
130static void xpad_pad_paste (XpadPad *pad);
131static void xpad_pad_delete (XpadPad *pad);
132static void xpad_pad_open_properties (XpadPad *pad);
133static void xpad_pad_open_preferences (XpadPad *pad);
134static void xpad_pad_close_all (XpadPad *pad);
135static void xpad_pad_sync_title (XpadPad *pad);
136static gboolean xpad_pad_leave_notify_event (GtkWidget *pad, GdkEventCrossing *event);
137static gboolean xpad_pad_enter_notify_event (GtkWidget *pad, GdkEventCrossing *event);
138
139/* Create a new empty pad. */102/* Create a new empty pad. */
140GtkWidget *103GtkWidget *
141xpad_pad_new (XpadPadGroup *group, XpadSettings *settings)104xpad_pad_new (XpadPadGroup *group,
105 XpadSettings *settings)
142{106{
143 return GTK_WIDGET (g_object_new (XPAD_TYPE_PAD, "group", group, "settings", settings, NULL));107 return GTK_WIDGET (g_object_new (XPAD_TYPE_PAD, "group", group, "settings", settings, NULL));
144}108}
145109
146/* Create a new pad based on the provided info-xxxxx file from the config directory and return this pad */110static void
147GtkWidget *111xpad_pad_sync_title (XpadPad *pad)
148xpad_pad_new_with_info (XpadPadGroup *group, XpadSettings *settings, const gchar *info_filename, gboolean *show)112{
149{113 GtkTextBuffer *buffer;
150 GtkWidget *pad = xpad_pad_new (group, settings);114 GtkTextIter s, e;
151 115 gchar *content, *end;
152 XPAD_PAD (pad)->priv->infoname = g_strdup (info_filename);116
153 xpad_pad_load_info (XPAD_PAD (pad), show);117 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
154 xpad_pad_load_content (XPAD_PAD (pad));118 gtk_text_buffer_get_bounds (buffer, &s, &e);
155 gtk_window_set_role (GTK_WINDOW (pad), XPAD_PAD (pad)->priv->infoname);119 content = gtk_text_buffer_get_text (buffer, &s, &e, FALSE);
156 120 end = g_utf8_strchr (content, -1, '\n');
157 return pad;121 if (end)
158}122 *end = '\0';
159123
160/* Create a new pad based on the provided filename from the command line */124 gtk_window_set_title (GTK_WINDOW (pad), g_strstrip (content));
161GtkWidget *125
162xpad_pad_new_from_file (XpadPadGroup *group, XpadSettings *settings, const gchar *filename)126 g_free (content);
163{127}
164 GtkWidget *pad = NULL;128
165 gchar *content;129static void
166 130xpad_pad_text_changed (XpadPad *pad,
167 content = fio_get_file (filename);131 GtkTextBuffer *buffer)
168 132{
169 if (!content)133 /* A dirty way to silence the compiler for these unused variables. */
170 {134 (void) buffer;
171 gchar *usertext = g_strdup_printf (_("Could not read file %s."), filename);135
172 xpad_app_error (NULL, usertext, NULL);136 /* set title */
173 g_free (usertext);
174 }
175 else
176 {
177 GtkTextBuffer *buffer;
178
179 xpad_periodic_init ();
180 xpad_periodic_set_callback ("save-content", (XpadPeriodicFunc) xpad_pad_save_content);
181
182 pad = xpad_pad_new (group, settings);
183 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (XPAD_PAD (pad)->priv->textview));
184
185 xpad_text_buffer_freeze_undo (XPAD_TEXT_BUFFER (buffer));
186 g_signal_handlers_block_by_func (buffer, xpad_pad_text_changed, pad);
187
188 xpad_text_buffer_set_text_with_tags (XPAD_TEXT_BUFFER (buffer), content ? content : "");
189 g_free (content);
190
191 g_signal_handlers_unblock_by_func (buffer, xpad_pad_text_changed, pad);
192 xpad_text_buffer_thaw_undo (XPAD_TEXT_BUFFER (buffer));
193
194 xpad_pad_text_changed(XPAD_PAD(pad), buffer);
195 }
196
197 return pad;
198}
199
200/* Class pad - constructor */
201static void
202xpad_pad_class_init (XpadPadClass *klass)
203{
204 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
205
206 gobject_class->constructed = xpad_pad_constructed;
207 gobject_class->set_property = xpad_pad_set_property;
208 gobject_class->get_property = xpad_pad_get_property;
209 gobject_class->dispose = xpad_pad_dispose;
210 gobject_class->finalize = xpad_pad_finalize;
211
212 signals[CLOSED] =
213 g_signal_new ("closed",
214 G_OBJECT_CLASS_TYPE (gobject_class),
215 G_SIGNAL_RUN_FIRST,
216 G_STRUCT_OFFSET (XpadPadClass, closed),
217 NULL, NULL,
218 g_cclosure_marshal_VOID__VOID,
219 G_TYPE_NONE,
220 0);
221
222 /* Properties */
223 obj_prop[PROP_GROUP] = g_param_spec_pointer ("group", "Pad group", "Pad group for this pad", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
224 obj_prop[PROP_SETTINGS] = g_param_spec_pointer ("settings", "Xpad settings", "Xpad global settings", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
225
226 g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_prop);
227}
228
229static void
230xpad_pad_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
231{
232 XpadPad *pad = XPAD_PAD (object);
233
234 switch (prop_id)
235 {
236 case PROP_GROUP:
237 pad->priv->group = g_value_get_pointer (value);
238 g_object_ref (pad->priv->group);
239 if (pad->priv->group)
240 xpad_pad_group_add (pad->priv->group, GTK_WIDGET (pad));
241 break;
242
243 case PROP_SETTINGS:
244 pad->priv->settings = g_value_get_pointer (value);
245 g_object_ref (pad->priv->settings);
246 break;
247
248 default:
249 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
250 break;
251 }
252}
253
254static void
255xpad_pad_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
256{
257 XpadPad *pad = XPAD_PAD (object);
258
259 switch (prop_id)
260 {
261 case PROP_GROUP:
262 g_value_set_pointer (value, pad->priv->group);
263 break;
264
265 case PROP_SETTINGS:
266 g_value_set_pointer (value, pad->priv->settings);
267 break;
268
269 default:
270 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271 break;
272 }
273}
274
275/* Class pad - initializer */
276static void
277xpad_pad_init (XpadPad *pad)
278{
279 pad->priv = xpad_pad_get_instance_private (pad);
280
281 pad->priv->x = 0;
282 pad->priv->y = 0;
283 pad->priv->location_valid = FALSE;
284 pad->priv->infoname = NULL;
285 pad->priv->contentname = NULL;
286 pad->priv->textview = NULL;
287 pad->priv->scrollbar = NULL;
288 pad->priv->toolbar = NULL;
289 pad->priv->toolbar_timeout = 0;
290 pad->priv->toolbar_height = 0;
291 pad->priv->toolbar_expanded = FALSE;
292 pad->priv->toolbar_pad_resized = TRUE;
293 pad->priv->properties = NULL;
294 pad->priv->unsaved_content = FALSE;
295 pad->priv->unsaved_info = FALSE;
296}
297
298static void xpad_pad_constructed (GObject *object)
299{
300 XpadPad *pad = XPAD_PAD (object);
301
302 gboolean decorations;
303 GtkBox *vbox;
304
305 g_object_get (pad->priv->settings,
306 "width", &pad->priv->width,
307 "height", &pad->priv->height,
308 "autostart-sticky", &pad->priv->sticky, NULL);
309
310 GtkWindow *pad_window = GTK_WINDOW (pad);
311
312 pad->priv->textview = GTK_WIDGET (XPAD_TEXT_VIEW (xpad_text_view_new (pad->priv->settings, pad)));
313
314 pad->priv->scrollbar = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
315 "hadjustment", NULL,
316 "hscrollbar-policy", GTK_POLICY_NEVER,
317 "shadow-type", GTK_SHADOW_NONE,
318 "vadjustment", NULL,
319 "vscrollbar-policy", GTK_POLICY_NEVER,
320 "child", pad->priv->textview,
321 NULL));
322
323 pad->priv->toolbar = GTK_WIDGET (xpad_toolbar_new (pad));
324
325 pad->priv->accel_group = gtk_accel_group_new ();
326 gtk_window_add_accel_group (pad_window, pad->priv->accel_group);
327 pad->priv->menu = menu_get_popup_no_highlight (pad, pad->priv->accel_group);
328 pad->priv->highlight_menu = menu_get_popup_highlight (pad, pad->priv->accel_group);
329 gtk_accel_group_connect (pad->priv->accel_group, GDK_KEY_Q, GDK_CONTROL_MASK, 0, g_cclosure_new_swap (G_CALLBACK (xpad_app_quit), pad, NULL));
330
331 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0));
332 gtk_box_set_homogeneous (vbox, FALSE);
333 gtk_box_pack_start (vbox, pad->priv->scrollbar, TRUE, TRUE, 0);
334 gtk_box_pack_start (vbox, pad->priv->toolbar, FALSE, FALSE, 0);
335
336 gtk_container_child_set (GTK_CONTAINER (vbox), pad->priv->toolbar, "expand", FALSE, NULL);
337
338 g_object_get (pad->priv->settings, "has-decorations", &decorations, NULL);
339 gtk_window_set_decorated (pad_window, decorations);
340 gtk_window_set_default_size (pad_window, (gint) pad->priv->width, (gint) pad->priv->height);
341 gtk_window_set_gravity (pad_window, GDK_GRAVITY_STATIC); /* static gravity makes saving pad x,y work */
342 gtk_window_set_skip_pager_hint (pad_window, decorations);
343 gtk_window_set_skip_taskbar_hint (pad_window, !decorations);
344 gtk_window_set_position (pad_window, GTK_WIN_POS_MOUSE);
345
346 g_object_set (G_OBJECT (pad), "child", vbox, NULL);
347
348 xpad_pad_notify_has_scrollbar (pad);
349 xpad_pad_notify_has_selection (pad);
350 xpad_pad_notify_clipboard_owner_changed (pad);
351 xpad_pad_notify_undo_redo_changed (pad);
352
353 pad->priv->clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
354
355 if (pad->priv->sticky)
356 gtk_window_stick (pad_window);
357 else
358 gtk_window_unstick (pad_window);
359
360 xpad_pad_sync_title (pad);137 xpad_pad_sync_title (pad);
361138
362 gtk_widget_show_all (GTK_WIDGET (vbox));139 /* record change */
363140 xpad_pad_save_content_delayed(pad);
364 gtk_widget_hide (pad->priv->toolbar);141}
365 xpad_pad_notify_has_toolbar (pad);142
366143void
367 /* Set up signals */144xpad_pad_load_content (XpadPad *pad)
368 gtk_widget_add_events (GTK_WIDGET (pad), GDK_BUTTON_PRESS_MASK | GDK_PROPERTY_CHANGE_MASK);145{
369 gtk_widget_add_events (pad->priv->toolbar, GDK_ALL_EVENTS_MASK);146 g_return_if_fail (pad);
370 g_signal_connect_swapped (pad->priv->textview, "button-press-event", G_CALLBACK (xpad_pad_button_press_event), pad);147
371 g_signal_connect_swapped (pad->priv->textview, "popup-menu", G_CALLBACK (xpad_pad_popup_menu), pad);148 gchar *content;
372 g_signal_connect_swapped (pad->priv->toolbar, "size-allocate", G_CALLBACK (xpad_pad_toolbar_size_allocate), pad);149 GtkTextBuffer *buffer;
373 g_signal_connect (pad, "button-press-event", G_CALLBACK (xpad_pad_button_press_event), NULL);150
374 g_signal_connect (pad, "configure-event", G_CALLBACK (xpad_pad_configure_event), NULL);151 if (!pad->priv->contentname)
375 g_signal_connect (pad, "delete-event", G_CALLBACK (xpad_pad_delete_event), NULL);152 return;
376 g_signal_connect (pad, "popup-menu", G_CALLBACK (xpad_pad_popup_menu), NULL);153
377 g_signal_connect (pad, "show", G_CALLBACK (xpad_pad_show), NULL);154 content = fio_get_file (pad->priv->contentname);
378 g_signal_connect_swapped (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)), "changed", G_CALLBACK (xpad_pad_text_changed), pad);155
379156 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
380 g_signal_connect (pad, "enter-notify-event", G_CALLBACK (xpad_pad_enter_notify_event), NULL);157
381 g_signal_connect (pad, "leave-notify-event", G_CALLBACK (xpad_pad_leave_notify_event), NULL);158 xpad_text_buffer_freeze_undo (XPAD_TEXT_BUFFER (buffer));
382159 g_signal_handlers_block_by_func (buffer, xpad_pad_text_changed, pad);
383 g_signal_connect_swapped (pad->priv->settings, "notify::has-decorations", G_CALLBACK (xpad_pad_notify_has_decorations), pad);160
384 g_signal_connect_swapped (pad->priv->settings, "notify::has-toolbar", G_CALLBACK (xpad_pad_notify_has_toolbar), pad);161 xpad_text_buffer_set_text_with_tags (XPAD_TEXT_BUFFER (buffer), content ? content : "");
385 g_signal_connect_swapped (pad->priv->settings, "notify::autohide-toolbar", G_CALLBACK (xpad_pad_notify_autohide_toolbar), pad);162 g_free (content);
386 g_signal_connect_swapped (pad->priv->settings, "notify::has-scrollbar", G_CALLBACK (xpad_pad_notify_has_scrollbar), pad);163
387 g_signal_connect_swapped (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)), "notify::has-selection", G_CALLBACK (xpad_pad_notify_has_selection), pad);164 g_signal_handlers_unblock_by_func (buffer, xpad_pad_text_changed, pad);
388 g_signal_connect_swapped (pad->priv->clipboard, "owner-change", G_CALLBACK (xpad_pad_notify_clipboard_owner_changed), pad);165 xpad_text_buffer_thaw_undo (XPAD_TEXT_BUFFER (buffer));
389166
390 g_signal_connect_swapped (pad->priv->toolbar, "activate-new", G_CALLBACK (xpad_pad_spawn), pad);167 xpad_pad_text_changed(pad, buffer);
391 g_signal_connect_swapped (pad->priv->toolbar, "activate-clear", G_CALLBACK (xpad_pad_clear), pad);168 pad->priv->unsaved_content = FALSE;
392 g_signal_connect_swapped (pad->priv->toolbar, "activate-close", G_CALLBACK (xpad_pad_close), pad);169}
393 g_signal_connect_swapped (pad->priv->toolbar, "activate-undo", G_CALLBACK (xpad_pad_undo), pad);170
394 g_signal_connect_swapped (pad->priv->toolbar, "activate-redo", G_CALLBACK (xpad_pad_redo), pad);171void
395 g_signal_connect_swapped (pad->priv->toolbar, "activate-cut", G_CALLBACK (xpad_pad_cut), pad);172xpad_pad_save_content (XpadPad *pad)
396 g_signal_connect_swapped (pad->priv->toolbar, "activate-copy", G_CALLBACK (xpad_pad_copy), pad);173{
397 g_signal_connect_swapped (pad->priv->toolbar, "activate-paste", G_CALLBACK (xpad_pad_paste), pad);174 g_return_if_fail (pad);
398 g_signal_connect_swapped (pad->priv->toolbar, "activate-delete", G_CALLBACK (xpad_pad_delete), pad);175
399 g_signal_connect_swapped (pad->priv->toolbar, "activate-properties", G_CALLBACK (xpad_pad_open_properties), pad);176 gchar *content;
400 g_signal_connect_swapped (pad->priv->toolbar, "activate-preferences", G_CALLBACK (xpad_pad_open_preferences), pad);177 GtkTextBuffer *buffer;
401 g_signal_connect_swapped (pad->priv->toolbar, "activate-quit", G_CALLBACK (xpad_pad_close_all), pad);178
402179 if (!pad->priv->unsaved_content)
403 g_signal_connect_swapped (pad->priv->toolbar, "popup", G_CALLBACK (menu_popup), pad);180 return;
404 g_signal_connect_swapped (pad->priv->toolbar, "popdown", G_CALLBACK (menu_popdown), pad);181
405182 /* create content file if it doesn't exist yet */
406 g_signal_connect_swapped (pad->priv->menu, "deactivate", G_CALLBACK (menu_popdown), pad);183 if (!pad->priv->contentname)
407 g_signal_connect_swapped (pad->priv->highlight_menu, "deactivate", G_CALLBACK (menu_popdown), pad);184 {
408}185 pad->priv->contentname = fio_unique_name ("content-");
409186 if (!pad->priv->contentname)
410static void187 return;
411xpad_pad_dispose (GObject *object)188 }
412{189
413 XpadPad *pad = XPAD_PAD (object);190 if (GTK_IS_TEXT_VIEW(pad->priv->textview)) {
414191 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
415 if (pad->priv->group) {192 content = xpad_text_buffer_get_text_with_tags (XPAD_TEXT_BUFFER (buffer));
416 g_object_unref(pad->priv->group);193 }
417 pad->priv->group = NULL;194 else
418 }195 g_warning("There is a problem in the program Xpad. In function 'xpad_pad_save_content' the variable 'pad->priv->textview' is not of type textview. Please send a bugreport to https://bugs.launchpad.net/xpad/+filebug to help improve Xpad.");
419196
420 if (GTK_IS_WIDGET(pad->priv->menu)) {197 fio_set_file (pad->priv->contentname, content);
421 gtk_widget_destroy (pad->priv->menu);198
422 pad->priv->menu = NULL;199 pad->priv->unsaved_content = FALSE;
423 }200 g_free (content);
424
425 if (GTK_IS_WIDGET(pad->priv->highlight_menu)) {
426 gtk_widget_destroy (pad->priv->highlight_menu);
427 pad->priv->highlight_menu = NULL;
428 }
429
430 if (XPAD_IS_PAD_PROPERTIES (pad->priv->properties)) {
431 gtk_widget_destroy (pad->priv->properties);
432 pad->priv->properties = NULL;
433 }
434
435 gtk_clipboard_clear (pad->priv->clipboard);
436
437 /* For some reason the toolbar handler does not get automatically disconnected (or not at the right moment), leading to errors after deleting a pad. This manual disconnect prevents this error. */
438 if (XPAD_IS_TOOLBAR (pad->priv->toolbar)) {
439 g_signal_handlers_disconnect_matched (pad->priv->toolbar, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, pad);
440 gtk_widget_destroy(pad->priv->toolbar);
441 pad->priv->toolbar = NULL;
442 }
443
444 G_OBJECT_CLASS (xpad_pad_parent_class)->dispose (object);
445}
446
447static void
448xpad_pad_finalize (GObject *object)
449{
450 XpadPad *pad = XPAD_PAD (object);
451
452 if (pad->priv->settings) {
453 g_signal_handlers_disconnect_matched (pad->priv->settings, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, pad);
454 g_object_unref(pad->priv->settings);
455 pad->priv->settings = NULL;
456 }
457
458 g_free (pad->priv->infoname);
459 g_free (pad->priv->contentname);
460
461 G_OBJECT_CLASS (xpad_pad_parent_class)->finalize (object);
462}
463
464static void
465xpad_pad_show (XpadPad *pad)
466{
467 /*
468 * Some wm's might not acknowledge our request for a specific
469 * location before we are shown. What we do here is a little gimpy
470 * and not very respectful of wms' sovereignty, but it has the effect
471 * of making pads' locations very dependable. We just move the pad
472 * again here after being shown. This may create a visual effect if
473 * the wm did ignore us, but is better than being in the wrong
474 * place, I guess.
475 */
476 if (pad->priv->location_valid)
477 gtk_window_move (GTK_WINDOW (pad), pad->priv->x, pad->priv->y);
478
479 if (pad->priv->sticky)
480 gtk_window_stick (GTK_WINDOW (pad));
481 else
482 gtk_window_unstick (GTK_WINDOW (pad));
483}
484
485static gboolean toolbar_timeout (XpadPad *pad)
486{
487 if (!pad || !pad->priv || !pad->priv->toolbar_timeout)
488 return FALSE;
489
490 gboolean has_toolbar, autohide_toolbar;
491 g_object_get (pad->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
492
493 if (pad->priv->toolbar_timeout && autohide_toolbar && has_toolbar)
494 xpad_pad_hide_toolbar (pad);
495
496 pad->priv->toolbar_timeout = 0;
497
498 return FALSE;
499}
500
501static void
502xpad_pad_notify_has_decorations (XpadPad *pad)
503{
504 GtkWidget *pad_widget = GTK_WIDGET (pad);
505 GtkWindow *pad_window = GTK_WINDOW (pad);
506 gboolean decorations;
507 g_object_get (pad->priv->settings, "has-decorations", &decorations, NULL);
508
509 /* Update pad menu with the new status */
510 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-decorations");
511 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), decorations);
512
513 /*
514 * There are two modes of operation: a normal mode and a 'stealth' mode.
515 * If decorations are disabled, we also don't show up in the taskbar or pager.
516 */
517 gtk_window_set_decorated (pad_window, decorations);
518 gtk_window_set_skip_taskbar_hint (pad_window, !decorations);
519 gtk_window_set_skip_pager_hint (pad_window, !decorations);
520
521 /*
522 * reshow_with_initial_size() seems to set the window back to a never-shown state.
523 * This is good, as some WMs don't like us changing the above parameters mid-run,
524 * even if we do a hide/show cycle.
525 */
526 gtk_window_set_default_size (pad_window, (gint) pad->priv->width, (gint) pad->priv->height);
527 gtk_widget_hide (pad_widget);
528 gtk_widget_unrealize (pad_widget);
529 gtk_widget_show (pad_widget);
530}
531
532static void
533xpad_pad_notify_has_toolbar (XpadPad *pad)
534{
535 gboolean has_toolbar, autohide_toolbar;
536 g_object_get (pad->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
537
538 /* Update pad menu with the new status */
539 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-toolbar");
540 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), has_toolbar);
541 menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-autohide-toolbar");
542 gtk_widget_set_sensitive (menu_item, has_toolbar);
543
544 if (has_toolbar && !autohide_toolbar)
545 xpad_pad_show_toolbar (pad);
546 else
547 xpad_pad_hide_toolbar (pad);
548}
549
550static void
551xpad_pad_notify_autohide_toolbar (XpadPad *pad)
552{
553 gboolean autohide_toolbar;
554 g_object_get (pad->priv->settings, "autohide-toolbar", &autohide_toolbar, NULL);
555
556 /* Update pad menu with the new status */
557 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-autohide-toolbar");
558 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), autohide_toolbar);
559
560 if (autohide_toolbar)
561 {
562 /* Likely not to be in pad when turning setting on */
563 if (!pad->priv->toolbar_timeout)
564 pad->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
565 }
566 else
567 {
568 gboolean has_toolbar;
569 g_object_get (pad->priv->settings, "has-toolbar", &has_toolbar, NULL);
570
571 if (has_toolbar)
572 xpad_pad_show_toolbar(pad);
573 }
574}
575
576static void
577xpad_pad_notify_has_scrollbar (XpadPad *pad)
578{
579 gboolean has_scrollbar;
580 g_object_get (pad->priv->settings, "has-scrollbar", &has_scrollbar, NULL);
581
582 /* Update pad menu with the new status */
583 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-scrollbar");
584 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), has_scrollbar);
585
586 if (has_scrollbar)
587 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pad->priv->scrollbar),
588 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
589 else
590 {
591 GtkAdjustment *v, *h;
592
593 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pad->priv->scrollbar),
594 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
595
596 /* now we need to adjust view so that user can see whole pad */
597 h = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (pad->priv->scrollbar));
598 v = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (pad->priv->scrollbar));
599
600 gtk_adjustment_set_value (h, 0);
601 gtk_adjustment_set_value (v, 0);
602 }
603}201}
604202
605static guint203static guint
@@ -629,6 +227,28 @@
629}227}
630228
631static void229static void
230xpad_pad_hide_toolbar (XpadPad *pad)
231{
232 if (gtk_widget_get_visible (pad->priv->toolbar))
233 {
234 GtkWidget *pad_widget = GTK_WIDGET (pad);
235 if (gtk_widget_get_window (pad_widget))
236 gdk_window_freeze_updates (gtk_widget_get_window (pad_widget));
237 gtk_widget_hide (pad->priv->toolbar);
238
239 if (pad->priv->toolbar_expanded ||
240 (pad->priv->toolbar_pad_resized && xpad_pad_text_and_toolbar_height (pad) >= pad->priv->height))
241 {
242 pad->priv->height -= pad->priv->toolbar_height;
243 gtk_window_resize (GTK_WINDOW (pad), (gint) pad->priv->width, (gint) pad->priv->height);
244 pad->priv->toolbar_expanded = FALSE;
245 }
246 if (gtk_widget_get_window (pad_widget))
247 gdk_window_thaw_updates (gtk_widget_get_window (pad_widget));
248 }
249}
250
251static void
632xpad_pad_show_toolbar (XpadPad *pad)252xpad_pad_show_toolbar (XpadPad *pad)
633{253{
634 if (!gtk_widget_get_visible (pad->priv->toolbar))254 if (!gtk_widget_get_visible (pad->priv->toolbar))
@@ -669,558 +289,10 @@
669 }289 }
670}290}
671291
672static void
673xpad_pad_hide_toolbar (XpadPad *pad)
674{
675 if (gtk_widget_get_visible (pad->priv->toolbar))
676 {
677 GtkWidget *pad_widget = GTK_WIDGET (pad);
678 if (gtk_widget_get_window (pad_widget))
679 gdk_window_freeze_updates (gtk_widget_get_window (pad_widget));
680 gtk_widget_hide (pad->priv->toolbar);
681
682 if (pad->priv->toolbar_expanded ||
683 (pad->priv->toolbar_pad_resized && xpad_pad_text_and_toolbar_height (pad) >= pad->priv->height))
684 {
685 pad->priv->height -= pad->priv->toolbar_height;
686 gtk_window_resize (GTK_WINDOW (pad), (gint) pad->priv->width, (gint) pad->priv->height);
687 pad->priv->toolbar_expanded = FALSE;
688 }
689 if (gtk_widget_get_window (pad_widget))
690 gdk_window_thaw_updates (gtk_widget_get_window (pad_widget));
691 }
692}
693
694void
695xpad_pad_notify_has_selection (XpadPad *pad)
696{
697 g_return_if_fail (pad);
698
699 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
700 gboolean has_selection = gtk_text_buffer_get_has_selection (buffer);
701
702 XpadToolbar *toolbar = XPAD_TOOLBAR (pad->priv->toolbar);
703 if (toolbar == NULL)
704 return;
705
706 xpad_toolbar_enable_cut_button (toolbar, has_selection);
707 xpad_toolbar_enable_copy_button (toolbar, has_selection);
708}
709
710void
711xpad_pad_notify_clipboard_owner_changed (XpadPad *pad)
712{
713 g_return_if_fail (pad);
714
715 /* safe cast to toolbar */
716 if (XPAD_IS_TOOLBAR (pad->priv->toolbar)) {
717 XpadToolbar *toolbar = XPAD_TOOLBAR (pad->priv->toolbar);
718 g_return_if_fail (toolbar);
719
720 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
721 xpad_toolbar_enable_paste_button (toolbar, gtk_clipboard_wait_is_text_available (clipboard));
722 }
723}
724
725void
726xpad_pad_notify_undo_redo_changed (XpadPad *pad)
727{
728 g_return_if_fail (pad);
729
730 XpadTextBuffer *buffer = NULL;
731 buffer = XPAD_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)));
732 g_return_if_fail (buffer);
733
734 XpadToolbar *toolbar = NULL;
735 toolbar = XPAD_TOOLBAR (pad->priv->toolbar);
736 g_return_if_fail (toolbar);
737
738 xpad_toolbar_enable_undo_button (toolbar, xpad_text_buffer_undo_available (buffer));
739 xpad_toolbar_enable_redo_button (toolbar, xpad_text_buffer_redo_available (buffer));
740}
741
742static gboolean
743xpad_pad_enter_notify_event (GtkWidget *pad, GdkEventCrossing *event)
744{
745 gboolean has_toolbar, autohide_toolbar;
746 g_object_get (XPAD_PAD (pad)->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
747
748 if (has_toolbar && autohide_toolbar &&
749 event->detail != GDK_NOTIFY_INFERIOR &&
750 event->mode == GDK_CROSSING_NORMAL)
751 {
752 XPAD_PAD (pad)->priv->toolbar_timeout = 0;
753 xpad_pad_show_toolbar (XPAD_PAD (pad));
754 }
755
756 return FALSE;
757}
758
759static gboolean
760xpad_pad_leave_notify_event (GtkWidget *pad, GdkEventCrossing *event)
761{
762 gboolean has_toolbar, autohide_toolbar;
763 g_object_get (XPAD_PAD (pad)->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
764
765 if (has_toolbar && autohide_toolbar &&
766 event->detail != GDK_NOTIFY_INFERIOR &&
767 event->mode == GDK_CROSSING_NORMAL)
768 {
769 if (!XPAD_PAD (pad)->priv->toolbar_timeout)
770 XPAD_PAD (pad)->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
771 }
772
773 return FALSE;
774}
775
776static void
777xpad_pad_spawn (XpadPad *pad)
778{
779 GtkWidget *newpad = xpad_pad_new (pad->priv->group, pad->priv->settings);
780 gtk_widget_show (newpad);
781}
782
783static void
784xpad_pad_clear (XpadPad *pad)
785{
786 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
787 gtk_text_buffer_set_text (buffer, "", -1);
788}
789
790void
791xpad_pad_close (XpadPad *pad)
792{
793 gtk_widget_hide (GTK_WIDGET (pad));
794
795 /*
796 * If no tray and this is the last pad, we don't want to record this
797 * pad as closed, we want to start with just this pad next open. So
798 * quit before we record.
799 */
800 if (!xpad_tray_is_open () &&
801 xpad_pad_group_num_visible_pads (pad->priv->group) == 0)
802 {
803 xpad_app_quit ();
804 return;
805 }
806
807 if (pad->priv->properties)
808 gtk_widget_destroy (pad->priv->properties);
809
810 xpad_pad_save_info (pad);
811
812 g_signal_emit (pad, signals[CLOSED], 0);
813}
814
815void
816xpad_pad_toggle(XpadPad *pad)
817{
818 if (gtk_widget_get_visible (GTK_WIDGET(pad)))
819 xpad_pad_close (pad);
820 else
821 gtk_widget_show (GTK_WIDGET (pad));
822}
823
824static gboolean
825should_confirm_delete (XpadPad *pad)
826{
827 GtkTextBuffer *buffer;
828 GtkTextIter s, e;
829 gchar *content;
830 gboolean confirm;
831
832 g_object_get (pad->priv->settings, "confirm-destroy", &confirm, NULL);
833 if (!confirm)
834 return FALSE;
835
836 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
837 gtk_text_buffer_get_bounds (buffer, &s, &e);
838 content = gtk_text_buffer_get_text (buffer, &s, &e, FALSE);
839
840 confirm = strcmp (g_strstrip (content), "") != 0;
841
842 g_free (content);
843
844 return confirm;
845}
846
847static void
848xpad_pad_delete (XpadPad *pad)
849{
850 g_return_if_fail (pad);
851
852 /* With the delayed saving functionality, it is necessary to clear the unsaved flags to prevent usage of non-existing object information. */
853 pad->priv->unsaved_info = FALSE;
854 pad->priv->unsaved_content = FALSE;
855
856 if (should_confirm_delete (pad))
857 {
858 GtkWidget *dialog;
859 gint response;
860
861 dialog = xpad_app_alert_dialog (GTK_WINDOW (pad), "dialog-warning", _("Delete this pad?"), _("All text of this pad will be irrevocably lost."));
862
863 if (!dialog)
864 return;
865
866 gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Delete"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
867
868 response = gtk_dialog_run (GTK_DIALOG (dialog));
869
870 gtk_widget_destroy (dialog);
871
872 if (response != GTK_RESPONSE_ACCEPT)
873 return;
874 }
875
876 /* These two if statements actually erase the pad on the harddisk. */
877 if (pad->priv->infoname)
878 fio_remove_file (pad->priv->infoname);
879 if (pad->priv->contentname)
880 fio_remove_file (pad->priv->contentname);
881
882 /* Remove the pad from the group and destroy it. */
883 gtk_widget_destroy (GTK_WIDGET (pad));
884}
885
886static void
887pad_properties_sync_title (XpadPad *pad)
888{
889 gchar *title;
890
891 if (!pad->priv->properties)
892 return;
893
894 title = g_strdup_printf (_("'%s' Properties"), gtk_window_get_title (GTK_WINDOW (pad)));
895 gtk_window_set_title (GTK_WINDOW (pad->priv->properties), title);
896 g_free (title);
897}
898
899static void
900pad_properties_destroyed (XpadPad *pad)
901{
902 if (!pad->priv->properties)
903 return;
904
905 g_signal_handlers_disconnect_by_func (pad, (gpointer) pad_properties_sync_title, NULL);
906 pad->priv->properties = NULL;
907}
908
909static void
910prop_notify_font (XpadPad *pad)
911{
912 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (pad->priv->properties);
913
914 gboolean follow_font_style;
915 g_object_get (prop, "follow-font-style", &follow_font_style, NULL);
916 g_object_set (XPAD_TEXT_VIEW (pad->priv->textview), "follow-font-style", follow_font_style, NULL);
917
918 if (!follow_font_style)
919 {
920 const gchar *font;
921 g_object_get (prop, "fontname", &font, NULL);
922 PangoFontDescription *fontdesc;
923
924 fontdesc = font ? pango_font_description_from_string (font) : NULL;
925 gtk_widget_override_font (pad->priv->textview, fontdesc);
926 if (fontdesc)
927 pango_font_description_free (fontdesc);
928 }
929
930 xpad_pad_save_info_delayed (pad);
931}
932
933static void
934prop_notify_colors (XpadPad *pad)
935{
936 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (pad->priv->properties);
937
938 gboolean follow_color_style;
939 const GdkRGBA *text_color, *back_color;
940
941 g_object_get (prop, "follow-color-style", &follow_color_style, NULL);
942 g_object_set (XPAD_TEXT_VIEW (pad->priv->textview), "follow-color-style", follow_color_style, NULL);
943
944 if (follow_color_style)
945 /* Set the colors to the global preferences colors */
946 g_object_get (pad->priv->settings, "text-color", &text_color, "back-color", &back_color, NULL);
947 else
948 /* Set the color to the individual pad properties colors */
949 g_object_get (prop, "text-color", &text_color, "back-color", &back_color, NULL);
950
951 gtk_widget_override_cursor (pad->priv->textview, text_color, text_color);
952 gtk_widget_override_color (pad->priv->textview, GTK_STATE_FLAG_NORMAL, text_color);
953 gtk_widget_override_background_color (pad->priv->textview, GTK_STATE_FLAG_NORMAL, back_color);
954
955 /* Inverse the text and background colors for selected text, so it is likely to be visible by any choice of the colors. */
956 gtk_widget_override_color (pad->priv->textview, GTK_STATE_FLAG_SELECTED, back_color);
957 gtk_widget_override_background_color (pad->priv->textview, GTK_STATE_FLAG_SELECTED, text_color);
958
959 xpad_pad_save_info_delayed (pad);
960}
961
962static void
963xpad_pad_open_properties (XpadPad *pad)
964{
965 gboolean follow_font_style, follow_color_style;
966 GtkStyleContext *style = NULL;
967 PangoFontDescription *font;
968 GdkRGBA widget_text_color = {0, 0, 0, 0};
969 GdkRGBA widget_background_color = {0, 0, 0, 0};
970
971 if (pad->priv->properties)
972 {
973 gtk_window_present (GTK_WINDOW (pad->priv->properties));
974 return;
975 }
976
977 pad->priv->properties = xpad_pad_properties_new ();
978
979 gtk_window_set_transient_for (GTK_WINDOW (pad->priv->properties), GTK_WINDOW (pad));
980 gtk_window_set_resizable (GTK_WINDOW (pad->priv->properties), FALSE);
981
982 g_signal_connect_swapped (pad->priv->properties, "destroy", G_CALLBACK (pad_properties_destroyed), pad);
983 g_signal_connect (pad, "notify::title", G_CALLBACK (pad_properties_sync_title), NULL);
984
985 style = gtk_widget_get_style_context (pad->priv->textview);
986 gtk_style_context_get(style, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font, NULL);
987 gtk_style_context_get_color (style, GTK_STATE_FLAG_NORMAL, &widget_text_color);
988 gtk_style_context_get_background_color (style, GTK_STATE_FLAG_NORMAL, &widget_background_color);
989
990 g_object_get (XPAD_TEXT_VIEW (pad->priv->textview), "follow-font-style", &follow_font_style, "follow-color-style", &follow_color_style, NULL);
991 g_object_set (G_OBJECT (pad->priv->properties),
992 "follow-font-style", follow_font_style,
993 "follow-color-style", follow_color_style,
994 "text-color", &widget_text_color,
995 "back-color", &widget_background_color,
996 "fontname", pango_font_description_to_string(font),
997 NULL);
998 pango_font_description_free (font);
999
1000 g_signal_connect_swapped (pad->priv->properties, "notify::follow-font-style", G_CALLBACK (prop_notify_font), pad);
1001 g_signal_connect_swapped (pad->priv->properties, "notify::follow-color-style", G_CALLBACK (prop_notify_colors), pad);
1002 g_signal_connect_swapped (pad->priv->properties, "notify::text-color", G_CALLBACK (prop_notify_colors), pad);
1003 g_signal_connect_swapped (pad->priv->properties, "notify::back-color", G_CALLBACK (prop_notify_colors), pad);
1004 g_signal_connect_swapped (pad->priv->properties, "notify::fontname", G_CALLBACK (prop_notify_font), pad);
1005
1006 pad_properties_sync_title (pad);
1007
1008 gtk_widget_show (pad->priv->properties);
1009}
1010
1011static void
1012xpad_pad_open_preferences (XpadPad *pad)
1013{
1014 xpad_preferences_open (pad->priv->settings);
1015}
1016
1017static void
1018xpad_pad_text_changed (XpadPad *pad, GtkTextBuffer *buffer)
1019{
1020 /* A dirty way to silence the compiler for these unused variables. */
1021 (void) buffer;
1022
1023 /* set title */
1024 xpad_pad_sync_title (pad);
1025
1026 /* record change */
1027 xpad_pad_save_content_delayed(pad);
1028}
1029
1030static gboolean
1031xpad_pad_toolbar_size_allocate (XpadPad *pad, GtkAllocation *event)
1032{
1033 /* safe cast from gint to guint */
1034 if (event->height >= 0) {
1035 pad->priv->toolbar_height = (guint) event->height;
1036 }
1037 else {
1038 g_warning("There is a problem in the program Xpad. In function 'xpad_pad_toolbar_size_allocate' the variable 'event->height' is not a postive number. Please send a bugreport to https://bugs.launchpad.net/xpad/+filebug to help improve Xpad.");
1039 pad->priv->toolbar_height = 0;
1040 }
1041 return FALSE;
1042}
1043
1044static gboolean
1045xpad_pad_configure_event (XpadPad *pad, GdkEventConfigure *event)
1046{
1047 if (!gtk_widget_get_visible (GTK_WIDGET(pad)))
1048 return FALSE;
1049
1050 int eWidth = event->width;
1051 int eHeight = event->height;
1052
1053 /* safe cast from gint to guint */
1054 if (eWidth >= 0 && eHeight >=0 ) {
1055 if (pad->priv->width != (guint) eWidth || pad->priv->height != (guint) eHeight)
1056 pad->priv->toolbar_pad_resized = TRUE;
1057
1058 pad->priv->width = (guint) event->width;
1059 pad->priv->height = (guint) event->height;
1060 }
1061 else {
1062 g_warning("There is a problem in the program Xpad. In function 'xpad_pad_configure_event' the variable 'event->width' or 'event->height' is not a postive number. Please send a bugreport to https://bugs.launchpad.net/xpad/+filebug to help improve Xpad.");
1063 }
1064
1065 pad->priv->x = event->x;
1066 pad->priv->y = event->y;
1067 pad->priv->location_valid = TRUE;
1068
1069 xpad_pad_save_info_delayed(pad);
1070
1071 /*
1072 * Sometimes when moving, if the toolbar tries to hide itself,
1073 * the window manager will not resize it correctly. So, we make
1074 * sure not to end the timeout while moving.
1075 */
1076 if (pad->priv->toolbar_timeout)
1077 {
1078 g_source_remove (pad->priv->toolbar_timeout);
1079 pad->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
1080 }
1081
1082 return FALSE;
1083}
1084
1085static gboolean
1086xpad_pad_delete_event (XpadPad *pad, GdkEvent *event)
1087{
1088 /* A dirty way to silence the compiler for these unused variables. */
1089 (void) event;
1090
1091 xpad_pad_close (pad);
1092
1093 return TRUE;
1094}
1095
1096static gboolean
1097xpad_pad_popup_menu (XpadPad *pad)
1098{
1099 xpad_pad_popup (pad, NULL);
1100
1101 return TRUE;
1102}
1103
1104static gboolean
1105xpad_pad_button_press_event (XpadPad *pad, GdkEventButton *event)
1106{
1107 if (event->type == GDK_BUTTON_PRESS)
1108 {
1109 switch (event->button)
1110 {
1111 case 1:
1112 if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK)
1113 {
1114 gtk_window_begin_move_drag (GTK_WINDOW (pad), (gint) event->button, (gint) event->x_root, (gint) event->y_root, event->time);
1115 return TRUE;
1116 }
1117 break;
1118
1119 case 3:
1120 if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK)
1121 {
1122 GdkWindowEdge edge;
1123
1124 if (gtk_widget_get_direction (GTK_WIDGET (pad)) == GTK_TEXT_DIR_LTR)
1125 edge = GDK_WINDOW_EDGE_SOUTH_EAST;
1126 else
1127 edge = GDK_WINDOW_EDGE_SOUTH_WEST;
1128
1129 gtk_window_begin_resize_drag (GTK_WINDOW (pad), edge, (gint) event->button, (gint) event->x_root, (gint) event->y_root, event->time);
1130 }
1131 else
1132 {
1133 xpad_pad_popup (pad, event);
1134 }
1135 return TRUE;
1136 }
1137 }
1138
1139 return FALSE;
1140}
1141
1142static void
1143xpad_pad_sync_title (XpadPad *pad)
1144{
1145 GtkTextBuffer *buffer;
1146 GtkTextIter s, e;
1147 gchar *content, *end;
1148
1149 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
1150 gtk_text_buffer_get_bounds (buffer, &s, &e);
1151 content = gtk_text_buffer_get_text (buffer, &s, &e, FALSE);
1152 end = g_utf8_strchr (content, -1, '\n');
1153 if (end)
1154 *end = '\0';
1155
1156 gtk_window_set_title (GTK_WINDOW (pad), g_strstrip (content));
1157
1158 g_free (content);
1159}
1160
1161void
1162xpad_pad_load_content (XpadPad *pad)
1163{
1164 g_return_if_fail (pad);
1165
1166 gchar *content;
1167 GtkTextBuffer *buffer;
1168
1169 if (!pad->priv->contentname)
1170 return;
1171
1172 content = fio_get_file (pad->priv->contentname);
1173
1174 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
1175
1176 xpad_text_buffer_freeze_undo (XPAD_TEXT_BUFFER (buffer));
1177 g_signal_handlers_block_by_func (buffer, xpad_pad_text_changed, pad);
1178
1179 xpad_text_buffer_set_text_with_tags (XPAD_TEXT_BUFFER (buffer), content ? content : "");
1180 g_free (content);
1181
1182 g_signal_handlers_unblock_by_func (buffer, xpad_pad_text_changed, pad);
1183 xpad_text_buffer_thaw_undo (XPAD_TEXT_BUFFER (buffer));
1184
1185 xpad_pad_text_changed(pad, buffer);
1186 pad->priv->unsaved_content = FALSE;
1187}
1188
1189void
1190xpad_pad_save_content (XpadPad *pad)
1191{
1192 g_return_if_fail (pad);
1193
1194 gchar *content;
1195 GtkTextBuffer *buffer;
1196
1197 if (!pad->priv->unsaved_content)
1198 return;
1199
1200 /* create content file if it doesn't exist yet */
1201 if (!pad->priv->contentname)
1202 {
1203 pad->priv->contentname = fio_unique_name ("content-");
1204 if (!pad->priv->contentname)
1205 return;
1206 }
1207
1208 if (GTK_IS_TEXT_VIEW(pad->priv->textview)) {
1209 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
1210 content = xpad_text_buffer_get_text_with_tags (XPAD_TEXT_BUFFER (buffer));
1211 }
1212 else
1213 g_warning("There is a problem in the program Xpad. In function 'xpad_pad_save_content' the variable 'pad->priv->textview' is not of type textview. Please send a bugreport to https://bugs.launchpad.net/xpad/+filebug to help improve Xpad.");
1214
1215 fio_set_file (pad->priv->contentname, content);
1216
1217 pad->priv->unsaved_content = FALSE;
1218 g_free (content);
1219}
1220
1221/* Extract all the metadata of a single pad from its info-xxxxx file and store it in the pad object */292/* Extract all the metadata of a single pad from its info-xxxxx file and store it in the pad object */
1222static void293static void
1223xpad_pad_load_info (XpadPad *pad, gboolean *show)294xpad_pad_load_info (XpadPad *pad,
295 gboolean *show)
1224{296{
1225 gboolean locked = FALSE, follow_font = TRUE, follow_color = TRUE, hidden = FALSE;297 gboolean locked = FALSE, follow_font = TRUE, follow_color = TRUE, hidden = FALSE;
1226 gboolean has_toolbar, autohide_toolbar;298 gboolean has_toolbar, autohide_toolbar;
@@ -1406,29 +478,142 @@
1406 pad->priv->unsaved_info = FALSE;478 pad->priv->unsaved_info = FALSE;
1407}479}
1408480
1409static void481/* Create a new pad based on the provided info-xxxxx file from the config directory and return this pad */
1410menu_about (XpadPad *pad)482GtkWidget *
1411{483xpad_pad_new_with_info (XpadPadGroup *group,
1412 const gchar *artists[] = {"Michael Terry <mike@mterry.name>", NULL};484 XpadSettings *settings,
1413 const gchar *authors[] = {"Arthur Borsboom <arthurborsboom@gmail.com>", "Jeroen Vermeulen <jtv@xs4all.nl>", "Michael Terry <mike@mterry.name>", "Paul Ivanov <pivanov@berkeley.edu>", "Sachin Raut <great.sachin@gmail.com>", NULL};485 const gchar *info_filename,
1414 const gchar *comments = _("Sticky notes");486 gboolean *show)
1415 const gchar *copyright = "© 2001-2014 Michael Terry";487{
1416 /* Translators: please translate this as your own name and optionally email488 GtkWidget *pad = xpad_pad_new (group, settings);
1417 like so: "Your Name <your@email.com>" */489
1418 const gchar *translator_credits = _("translator-credits");490 XPAD_PAD (pad)->priv->infoname = g_strdup (info_filename);
1419 const gchar *website = "https://launchpad.net/xpad";491 xpad_pad_load_info (XPAD_PAD (pad), show);
1420 492 xpad_pad_load_content (XPAD_PAD (pad));
1421 gtk_show_about_dialog (GTK_WINDOW (pad),493 gtk_window_set_role (GTK_WINDOW (pad), XPAD_PAD (pad)->priv->infoname);
1422 "artists", artists,494
1423 "authors", authors,495 return pad;
1424 "comments", comments,496}
1425 "copyright", copyright,497
1426 "license-type", GTK_LICENSE_GPL_3_0,498/* Create a new pad based on the provided filename from the command line */
1427 "logo-icon-name", PACKAGE,499GtkWidget *
1428 "translator-credits", translator_credits,500xpad_pad_new_from_file (XpadPadGroup *group,
1429 "version", VERSION,501 XpadSettings *settings,
1430 "website", website,502 const gchar *filename)
1431 NULL);503{
504 GtkWidget *pad = NULL;
505 gchar *content;
506
507 content = fio_get_file (filename);
508
509 if (!content)
510 {
511 gchar *usertext = g_strdup_printf (_("Could not read file %s."), filename);
512 xpad_app_error (NULL, usertext, NULL);
513 g_free (usertext);
514 }
515 else
516 {
517 GtkTextBuffer *buffer;
518
519 xpad_periodic_init ();
520 xpad_periodic_set_callback ("save-content", (XpadPeriodicFunc) xpad_pad_save_content);
521
522 pad = xpad_pad_new (group, settings);
523 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (XPAD_PAD (pad)->priv->textview));
524
525 xpad_text_buffer_freeze_undo (XPAD_TEXT_BUFFER (buffer));
526 g_signal_handlers_block_by_func (buffer, xpad_pad_text_changed, pad);
527
528 xpad_text_buffer_set_text_with_tags (XPAD_TEXT_BUFFER (buffer), content ? content : "");
529 g_free (content);
530
531 g_signal_handlers_unblock_by_func (buffer, xpad_pad_text_changed, pad);
532 xpad_text_buffer_thaw_undo (XPAD_TEXT_BUFFER (buffer));
533
534 xpad_pad_text_changed(XPAD_PAD(pad), buffer);
535 }
536
537 return pad;
538}
539
540static void
541xpad_pad_set_property (GObject *object,
542 guint prop_id,
543 const GValue *value,
544 GParamSpec *pspec)
545{
546 XpadPad *pad = XPAD_PAD (object);
547
548 switch (prop_id)
549 {
550 case PROP_GROUP:
551 pad->priv->group = g_value_get_pointer (value);
552 g_object_ref (pad->priv->group);
553 if (pad->priv->group)
554 xpad_pad_group_add (pad->priv->group, GTK_WIDGET (pad));
555 break;
556
557 case PROP_SETTINGS:
558 pad->priv->settings = g_value_get_pointer (value);
559 g_object_ref (pad->priv->settings);
560 break;
561
562 default:
563 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
564 break;
565 }
566}
567
568static void
569xpad_pad_get_property (GObject *object,
570 guint prop_id,
571 GValue *value,
572 GParamSpec *pspec)
573{
574 XpadPad *pad = XPAD_PAD (object);
575
576 switch (prop_id)
577 {
578 case PROP_GROUP:
579 g_value_set_pointer (value, pad->priv->group);
580 break;
581
582 case PROP_SETTINGS:
583 g_value_set_pointer (value, pad->priv->settings);
584 break;
585
586 default:
587 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
588 break;
589 }
590}
591
592static void
593xpad_pad_spawn (XpadPad *pad)
594{
595 GtkWidget *newpad = xpad_pad_new (pad->priv->group, pad->priv->settings);
596 gtk_widget_show (newpad);
597}
598
599static void
600xpad_pad_undo (XpadPad *pad)
601{
602 g_return_if_fail (pad->priv->textview);
603 XpadTextBuffer *buffer = NULL;
604 buffer = XPAD_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)));
605 g_return_if_fail (buffer);
606 xpad_text_buffer_undo (buffer);
607}
608
609static void
610xpad_pad_redo (XpadPad *pad)
611{
612 g_return_if_fail (pad->priv->textview);
613 XpadTextBuffer *buffer = NULL;
614 buffer = XPAD_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)));
615 g_return_if_fail (buffer);
616 xpad_text_buffer_redo (buffer);
1432}617}
1433618
1434static void619static void
@@ -1459,26 +644,6 @@
1459}644}
1460645
1461static void646static void
1462xpad_pad_undo (XpadPad *pad)
1463{
1464 g_return_if_fail (pad->priv->textview);
1465 XpadTextBuffer *buffer = NULL;
1466 buffer = XPAD_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)));
1467 g_return_if_fail (buffer);
1468 xpad_text_buffer_undo (buffer);
1469}
1470
1471static void
1472xpad_pad_redo (XpadPad *pad)
1473{
1474 g_return_if_fail (pad->priv->textview);
1475 XpadTextBuffer *buffer = NULL;
1476 buffer = XPAD_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)));
1477 g_return_if_fail (buffer);
1478 xpad_text_buffer_redo (buffer);
1479}
1480
1481static void
1482xpad_pad_show_all (XpadPad *pad)647xpad_pad_show_all (XpadPad *pad)
1483{648{
1484 xpad_pad_group_show_all (pad->priv->group);649 xpad_pad_group_show_all (pad->priv->group);
@@ -1502,8 +667,202 @@
1502 xpad_app_quit ();667 xpad_app_quit ();
1503}668}
1504669
1505static void670static gboolean
1506menu_toggle_tag (XpadPad *pad, const gchar *name)671should_confirm_delete (XpadPad *pad)
672{
673 GtkTextBuffer *buffer;
674 GtkTextIter s, e;
675 gchar *content;
676 gboolean confirm;
677
678 g_object_get (pad->priv->settings, "confirm-destroy", &confirm, NULL);
679 if (!confirm)
680 return FALSE;
681
682 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
683 gtk_text_buffer_get_bounds (buffer, &s, &e);
684 content = gtk_text_buffer_get_text (buffer, &s, &e, FALSE);
685
686 confirm = strcmp (g_strstrip (content), "") != 0;
687
688 g_free (content);
689
690 return confirm;
691}
692
693static void
694xpad_pad_delete (XpadPad *pad)
695{
696 g_return_if_fail (pad);
697
698 /* With the delayed saving functionality, it is necessary to clear the unsaved flags to prevent usage of non-existing object information. */
699 pad->priv->unsaved_info = FALSE;
700 pad->priv->unsaved_content = FALSE;
701
702 if (should_confirm_delete (pad))
703 {
704 GtkWidget *dialog;
705 gint response;
706
707 dialog = xpad_app_alert_dialog (GTK_WINDOW (pad), "dialog-warning", _("Delete this pad?"), _("All text of this pad will be irrevocably lost."));
708
709 if (!dialog)
710 return;
711
712 gtk_dialog_add_buttons (GTK_DIALOG (dialog), _("_Delete"), GTK_RESPONSE_ACCEPT, _("_Cancel"), GTK_RESPONSE_REJECT, NULL);
713
714 response = gtk_dialog_run (GTK_DIALOG (dialog));
715
716 gtk_widget_destroy (dialog);
717
718 if (response != GTK_RESPONSE_ACCEPT)
719 return;
720 }
721
722 /* These two if statements actually erase the pad on the harddisk. */
723 if (pad->priv->infoname)
724 fio_remove_file (pad->priv->infoname);
725 if (pad->priv->contentname)
726 fio_remove_file (pad->priv->contentname);
727
728 /* Remove the pad from the group and destroy it. */
729 gtk_widget_destroy (GTK_WIDGET (pad));
730}
731
732static void
733pad_properties_sync_title (XpadPad *pad)
734{
735 gchar *title;
736
737 if (!pad->priv->properties)
738 return;
739
740 title = g_strdup_printf (_("'%s' Properties"), gtk_window_get_title (GTK_WINDOW (pad)));
741 gtk_window_set_title (GTK_WINDOW (pad->priv->properties), title);
742 g_free (title);
743}
744
745static void
746pad_properties_destroyed (XpadPad *pad)
747{
748 if (!pad->priv->properties)
749 return;
750
751 g_signal_handlers_disconnect_by_func (pad, (gpointer) pad_properties_sync_title, NULL);
752 pad->priv->properties = NULL;
753}
754
755static void
756prop_notify_font (XpadPad *pad)
757{
758 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (pad->priv->properties);
759
760 gboolean follow_font_style;
761 g_object_get (prop, "follow-font-style", &follow_font_style, NULL);
762 g_object_set (XPAD_TEXT_VIEW (pad->priv->textview), "follow-font-style", follow_font_style, NULL);
763
764 if (!follow_font_style)
765 {
766 const gchar *font;
767 g_object_get (prop, "fontname", &font, NULL);
768 PangoFontDescription *fontdesc;
769
770 fontdesc = font ? pango_font_description_from_string (font) : NULL;
771 gtk_widget_override_font (pad->priv->textview, fontdesc);
772 if (fontdesc)
773 pango_font_description_free (fontdesc);
774 }
775
776 xpad_pad_save_info_delayed (pad);
777}
778
779static void
780prop_notify_colors (XpadPad *pad)
781{
782 XpadPadProperties *prop = XPAD_PAD_PROPERTIES (pad->priv->properties);
783
784 gboolean follow_color_style;
785 const GdkRGBA *text_color, *back_color;
786
787 g_object_get (prop, "follow-color-style", &follow_color_style, NULL);
788 g_object_set (XPAD_TEXT_VIEW (pad->priv->textview), "follow-color-style", follow_color_style, NULL);
789
790 if (follow_color_style)
791 /* Set the colors to the global preferences colors */
792 g_object_get (pad->priv->settings, "text-color", &text_color, "back-color", &back_color, NULL);
793 else
794 /* Set the color to the individual pad properties colors */
795 g_object_get (prop, "text-color", &text_color, "back-color", &back_color, NULL);
796
797 gtk_widget_override_cursor (pad->priv->textview, text_color, text_color);
798 gtk_widget_override_color (pad->priv->textview, GTK_STATE_FLAG_NORMAL, text_color);
799 gtk_widget_override_background_color (pad->priv->textview, GTK_STATE_FLAG_NORMAL, back_color);
800
801 /* Inverse the text and background colors for selected text, so it is likely to be visible by any choice of the colors. */
802 gtk_widget_override_color (pad->priv->textview, GTK_STATE_FLAG_SELECTED, back_color);
803 gtk_widget_override_background_color (pad->priv->textview, GTK_STATE_FLAG_SELECTED, text_color);
804
805 xpad_pad_save_info_delayed (pad);
806}
807
808static void
809xpad_pad_open_properties (XpadPad *pad)
810{
811 gboolean follow_font_style, follow_color_style;
812 GtkStyleContext *style = NULL;
813 PangoFontDescription *font;
814 GdkRGBA widget_text_color = {0, 0, 0, 0};
815 GdkRGBA widget_background_color = {0, 0, 0, 0};
816
817 if (pad->priv->properties)
818 {
819 gtk_window_present (GTK_WINDOW (pad->priv->properties));
820 return;
821 }
822
823 pad->priv->properties = xpad_pad_properties_new ();
824
825 gtk_window_set_transient_for (GTK_WINDOW (pad->priv->properties), GTK_WINDOW (pad));
826 gtk_window_set_resizable (GTK_WINDOW (pad->priv->properties), FALSE);
827
828 g_signal_connect_swapped (pad->priv->properties, "destroy", G_CALLBACK (pad_properties_destroyed), pad);
829 g_signal_connect (pad, "notify::title", G_CALLBACK (pad_properties_sync_title), NULL);
830
831 style = gtk_widget_get_style_context (pad->priv->textview);
832 gtk_style_context_get(style, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font, NULL);
833 gtk_style_context_get_color (style, GTK_STATE_FLAG_NORMAL, &widget_text_color);
834 gtk_style_context_get_background_color (style, GTK_STATE_FLAG_NORMAL, &widget_background_color);
835
836 g_object_get (XPAD_TEXT_VIEW (pad->priv->textview), "follow-font-style", &follow_font_style, "follow-color-style", &follow_color_style, NULL);
837 g_object_set (G_OBJECT (pad->priv->properties),
838 "follow-font-style", follow_font_style,
839 "follow-color-style", follow_color_style,
840 "text-color", &widget_text_color,
841 "back-color", &widget_background_color,
842 "fontname", pango_font_description_to_string(font),
843 NULL);
844 pango_font_description_free (font);
845
846 g_signal_connect_swapped (pad->priv->properties, "notify::follow-font-style", G_CALLBACK (prop_notify_font), pad);
847 g_signal_connect_swapped (pad->priv->properties, "notify::follow-color-style", G_CALLBACK (prop_notify_colors), pad);
848 g_signal_connect_swapped (pad->priv->properties, "notify::text-color", G_CALLBACK (prop_notify_colors), pad);
849 g_signal_connect_swapped (pad->priv->properties, "notify::back-color", G_CALLBACK (prop_notify_colors), pad);
850 g_signal_connect_swapped (pad->priv->properties, "notify::fontname", G_CALLBACK (prop_notify_font), pad);
851
852 pad_properties_sync_title (pad);
853
854 gtk_widget_show (pad->priv->properties);
855}
856
857static void
858xpad_pad_open_preferences (XpadPad *pad)
859{
860 xpad_preferences_open (pad->priv->settings);
861}
862
863static void
864menu_toggle_tag (XpadPad *pad,
865 const gchar *name)
1507{866{
1508 g_return_if_fail (pad->priv->textview);867 g_return_if_fail (pad->priv->textview);
1509 XpadTextBuffer *buffer = NULL;868 XpadTextBuffer *buffer = NULL;
@@ -1541,7 +900,8 @@
1541 * because this function has been probably been called, because of a menu toggle.900 * because this function has been probably been called, because of a menu toggle.
1542 */901 */
1543static void902static void
1544menu_sticky (GtkCheckMenuItem *check, XpadPad *pad)903menu_sticky (GtkCheckMenuItem *check,
904 XpadPad *pad)
1545{905{
1546 pad->priv->sticky = gtk_check_menu_item_get_active (check);906 pad->priv->sticky = gtk_check_menu_item_get_active (check);
1547 if (pad->priv->sticky)907 if (pad->priv->sticky)
@@ -1552,31 +912,36 @@
1552}912}
1553913
1554static void914static void
1555menu_toolbar (GtkCheckMenuItem *check, XpadPad *pad)915menu_toolbar (GtkCheckMenuItem *check,
916 XpadPad *pad)
1556{917{
1557 g_object_set (pad->priv->settings, "has-toolbar", gtk_check_menu_item_get_active (check), NULL);918 g_object_set (pad->priv->settings, "has-toolbar", gtk_check_menu_item_get_active (check), NULL);
1558}919}
1559920
1560static void921static void
1561menu_scrollbar (GtkCheckMenuItem *check, XpadPad *pad)922menu_scrollbar (GtkCheckMenuItem *check,
923 XpadPad *pad)
1562{924{
1563 g_object_set (pad->priv->settings, "has-scrollbar", gtk_check_menu_item_get_active (check), NULL);925 g_object_set (pad->priv->settings, "has-scrollbar", gtk_check_menu_item_get_active (check), NULL);
1564}926}
1565927
1566static void928static void
1567menu_autohide (GtkCheckMenuItem *check, XpadPad *pad)929menu_autohide (GtkCheckMenuItem *check,
930 XpadPad *pad)
1568{931{
1569 g_object_set (pad->priv->settings, "autohide-toolbar", gtk_check_menu_item_get_active (check), NULL);932 g_object_set (pad->priv->settings, "autohide-toolbar", gtk_check_menu_item_get_active (check), NULL);
1570}933}
1571934
1572static void935static void
1573menu_decorated (GtkCheckMenuItem *check, XpadPad *pad)936menu_decorated (GtkCheckMenuItem *check,
937 XpadPad *pad)
1574{938{
1575 g_object_set (pad->priv->settings, "has-decorations", gtk_check_menu_item_get_active (check), NULL);939 g_object_set (pad->priv->settings, "has-decorations", gtk_check_menu_item_get_active (check), NULL);
1576}940}
1577941
1578static gint942static gint
1579menu_title_compare (GtkWindow *a, GtkWindow *b)943menu_title_compare (GtkWindow *a,
944 GtkWindow *b)
1580{945{
1581 gchar *title_a = g_utf8_casefold (gtk_window_get_title (a), -1);946 gchar *title_a = g_utf8_casefold (gtk_window_get_title (a), -1);
1582 gchar *title_b = g_utf8_casefold (gtk_window_get_title (b), -1);947 gchar *title_b = g_utf8_casefold (gtk_window_get_title (b), -1);
@@ -1589,6 +954,31 @@
1589 return rv;954 return rv;
1590}955}
1591956
957static void
958menu_about (XpadPad *pad)
959{
960 const gchar *artists[] = {"Michael Terry <mike@mterry.name>", NULL};
961 const gchar *authors[] = {"Arthur Borsboom <arthurborsboom@gmail.com>", "Jeroen Vermeulen <jtv@xs4all.nl>", "Michael Terry <mike@mterry.name>", "Paul Ivanov <pivanov@berkeley.edu>", "Sachin Raut <great.sachin@gmail.com>", NULL};
962 const gchar *comments = _("Sticky notes");
963 const gchar *copyright = "© 2001-2014 Michael Terry";
964 /* Translators: please translate this as your own name and optionally email
965 like so: "Your Name <your@email.com>" */
966 const gchar *translator_credits = _("translator-credits");
967 const gchar *website = "https://launchpad.net/xpad";
968
969 gtk_show_about_dialog (GTK_WINDOW (pad),
970 "artists", artists,
971 "authors", authors,
972 "comments", comments,
973 "copyright", copyright,
974 "license-type", GTK_LICENSE_GPL_3_0,
975 "logo-icon-name", PACKAGE,
976 "translator-credits", translator_credits,
977 "version", VERSION,
978 "website", website,
979 NULL);
980}
981
1592/* FIXME: Accelerators are working but not visible for menu items with an image (icon). */982/* FIXME: Accelerators are working but not visible for menu items with an image (icon). */
1593#define MENU_ADD(mnemonic, image, key, mask, callback) {\983#define MENU_ADD(mnemonic, image, key, mask, callback) {\
1594 if (image) {\984 if (image) {\
@@ -1621,7 +1011,32 @@
1621 }1011 }
16221012
1623static GtkWidget *1013static GtkWidget *
1624menu_get_popup_no_highlight (XpadPad *pad, GtkAccelGroup *accel_group)1014menu_get_popup_highlight (XpadPad *pad,
1015 GtkAccelGroup *accel_group)
1016{
1017 GtkWidget *menu, *item;
1018
1019 menu = gtk_menu_new ();
1020 gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
1021
1022 MENU_ADD (_("Cu_t"), "edit-cut", 0, 0, xpad_pad_cut);
1023 MENU_ADD (_("_Copy"), "edit-copy", 0, 0, xpad_pad_copy);
1024 MENU_ADD (_("_Paste"), "edit-paste", 0, 0, xpad_pad_paste);
1025 g_object_set_data (G_OBJECT (menu), "paste", item);
1026 MENU_ADD_SEP ();
1027 MENU_ADD (_("_Bold"), "format-text-bold", GDK_KEY_b, GDK_CONTROL_MASK, menu_bold);
1028 MENU_ADD (_("_Italic"), "format-text-italic", GDK_KEY_i, GDK_CONTROL_MASK, menu_italic);
1029 MENU_ADD (_("_Underline"), "format-text-underline", GDK_KEY_u, GDK_CONTROL_MASK, menu_underline);
1030 MENU_ADD (_("_Strikethrough"), "format-text-strikethrough", 0, 0, menu_strikethrough);
1031
1032 gtk_widget_show_all (menu);
1033
1034 return menu;
1035}
1036
1037static GtkWidget *
1038menu_get_popup_no_highlight (XpadPad *pad,
1039 GtkAccelGroup *accel_group)
1625{1040{
1626 GtkWidget *uppermenu, *menu, *item;1041 GtkWidget *uppermenu, *menu, *item;
1627 gboolean has_toolbar, autohide_toolbar, has_scrollbar, decorations;1042 gboolean has_toolbar, autohide_toolbar, has_scrollbar, decorations;
@@ -1693,7 +1108,7 @@
1693 gtk_container_add (GTK_CONTAINER (uppermenu), item);1108 gtk_container_add (GTK_CONTAINER (uppermenu), item);
1694 menu = gtk_menu_new ();1109 menu = gtk_menu_new ();
1695 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);1110 gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), menu);
1696 MENU_ADD (_("_Help"), "help-browser", GDK_KEY_F1, 0, show_help); 1111 MENU_ADD (_("_Help"), "help-browser", GDK_KEY_F1, 0, show_help);
1697 MENU_ADD (_("_About"), "help-about", 0, 0, menu_about);1112 MENU_ADD (_("_About"), "help-about", 0, 0, menu_about);
1698 1113
1699 gtk_widget_show_all (uppermenu);1114 gtk_widget_show_all (uppermenu);
@@ -1702,7 +1117,139 @@
1702}1117}
17031118
1704static void1119static void
1705menu_prep_popup_no_highlight (XpadPad *pad, GtkWidget *uppermenu)1120xpad_pad_show (XpadPad *pad)
1121{
1122 /*
1123 * Some wm's might not acknowledge our request for a specific
1124 * location before we are shown. What we do here is a little gimpy
1125 * and not very respectful of wms' sovereignty, but it has the effect
1126 * of making pads' locations very dependable. We just move the pad
1127 * again here after being shown. This may create a visual effect if
1128 * the wm did ignore us, but is better than being in the wrong
1129 * place, I guess.
1130 */
1131 if (pad->priv->location_valid)
1132 gtk_window_move (GTK_WINDOW (pad), pad->priv->x, pad->priv->y);
1133
1134 if (pad->priv->sticky)
1135 gtk_window_stick (GTK_WINDOW (pad));
1136 else
1137 gtk_window_unstick (GTK_WINDOW (pad));
1138}
1139
1140static gboolean toolbar_timeout (XpadPad *pad)
1141{
1142 if (!pad || !pad->priv || !pad->priv->toolbar_timeout)
1143 return FALSE;
1144
1145 gboolean has_toolbar, autohide_toolbar;
1146 g_object_get (pad->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
1147
1148 if (pad->priv->toolbar_timeout && autohide_toolbar && has_toolbar)
1149 xpad_pad_hide_toolbar (pad);
1150
1151 pad->priv->toolbar_timeout = 0;
1152
1153 return FALSE;
1154}
1155
1156static gboolean
1157xpad_pad_configure_event (XpadPad *pad,
1158 GdkEventConfigure *event)
1159{
1160 if (!gtk_widget_get_visible (GTK_WIDGET(pad)))
1161 return FALSE;
1162
1163 int eWidth = event->width;
1164 int eHeight = event->height;
1165
1166 /* safe cast from gint to guint */
1167 if (eWidth >= 0 && eHeight >=0 ) {
1168 if (pad->priv->width != (guint) eWidth || pad->priv->height != (guint) eHeight)
1169 pad->priv->toolbar_pad_resized = TRUE;
1170
1171 pad->priv->width = (guint) event->width;
1172 pad->priv->height = (guint) event->height;
1173 }
1174 else {
1175 g_warning("There is a problem in the program Xpad. In function 'xpad_pad_configure_event' the variable 'event->width' or 'event->height' is not a postive number. Please send a bugreport to https://bugs.launchpad.net/xpad/+filebug to help improve Xpad.");
1176 }
1177
1178 pad->priv->x = event->x;
1179 pad->priv->y = event->y;
1180 pad->priv->location_valid = TRUE;
1181
1182 xpad_pad_save_info_delayed(pad);
1183
1184 /*
1185 * Sometimes when moving, if the toolbar tries to hide itself,
1186 * the window manager will not resize it correctly. So, we make
1187 * sure not to end the timeout while moving.
1188 */
1189 if (pad->priv->toolbar_timeout)
1190 {
1191 g_source_remove (pad->priv->toolbar_timeout);
1192 pad->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
1193 }
1194
1195 return FALSE;
1196}
1197
1198static gboolean
1199xpad_pad_toolbar_size_allocate (XpadPad *pad,
1200 GtkAllocation *event)
1201{
1202 /* safe cast from gint to guint */
1203 if (event->height >= 0) {
1204 pad->priv->toolbar_height = (guint) event->height;
1205 }
1206 else {
1207 g_warning("There is a problem in the program Xpad. In function 'xpad_pad_toolbar_size_allocate' the variable 'event->height' is not a postive number. Please send a bugreport to https://bugs.launchpad.net/xpad/+filebug to help improve Xpad.");
1208 pad->priv->toolbar_height = 0;
1209 }
1210 return FALSE;
1211}
1212
1213static gboolean
1214xpad_pad_delete_event (XpadPad *pad,
1215 GdkEvent *event)
1216{
1217 /* A dirty way to silence the compiler for these unused variables. */
1218 (void) event;
1219
1220 xpad_pad_close (pad);
1221
1222 return TRUE;
1223}
1224
1225static gboolean
1226xpad_pad_leave_notify_event (GtkWidget *pad,
1227 GdkEventCrossing *event)
1228{
1229 gboolean has_toolbar, autohide_toolbar;
1230 g_object_get (XPAD_PAD (pad)->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
1231
1232 if (has_toolbar && autohide_toolbar &&
1233 event->detail != GDK_NOTIFY_INFERIOR &&
1234 event->mode == GDK_CROSSING_NORMAL)
1235 {
1236 if (!XPAD_PAD (pad)->priv->toolbar_timeout)
1237 XPAD_PAD (pad)->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
1238 }
1239
1240 return FALSE;
1241}
1242
1243static void
1244menu_popup (XpadPad *pad)
1245{
1246 g_signal_handlers_block_matched (pad, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) xpad_pad_leave_notify_event, NULL);
1247 pad->priv->toolbar_timeout = 0;
1248}
1249
1250static void
1251menu_prep_popup_no_highlight (XpadPad *pad,
1252 GtkWidget *uppermenu)
1706{1253{
1707 GtkWidget *menu, *item;1254 GtkWidget *menu, *item;
17081255
@@ -1747,6 +1294,495 @@
1747 gtk_widget_show_all (menu);1294 gtk_widget_show_all (menu);
1748}1295}
17491296
1297static void
1298menu_prep_popup_highlight (XpadPad *pad,
1299 GtkWidget *menu)
1300{
1301 /* A dirty way to silence the compiler for these unused variables. */
1302 (void) pad;
1303
1304 GtkWidget *item;
1305 GtkClipboard *clipboard;
1306
1307 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1308
1309 item = g_object_get_data (G_OBJECT (menu), "paste");
1310 if (item)
1311 gtk_widget_set_sensitive (item, gtk_clipboard_wait_is_text_available (clipboard));
1312}
1313
1314static void
1315xpad_pad_popup (XpadPad *pad,
1316 GdkEventButton *event)
1317{
1318 GtkTextBuffer *buffer;
1319 GtkWidget *menu;
1320
1321 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
1322
1323 if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
1324 {
1325 menu = pad->priv->highlight_menu;
1326 menu_prep_popup_highlight (pad, menu);
1327 }
1328 else
1329 {
1330 menu = pad->priv->menu;
1331 menu_prep_popup_no_highlight (pad, menu);
1332 }
1333
1334 if (!menu)
1335 return;
1336
1337 menu_popup (pad);
1338
1339 if (event)
1340 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
1341 else
1342 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
1343}
1344
1345static gboolean
1346xpad_pad_popup_menu (XpadPad *pad)
1347{
1348 xpad_pad_popup (pad, NULL);
1349
1350 return TRUE;
1351}
1352
1353static void
1354menu_popdown (XpadPad *pad)
1355{
1356 cairo_rectangle_int_t rect;
1357
1358 /* We must check if we disabled off of pad and start the timeout if so. */
1359 rect.x = 10;
1360 rect.y = 10;
1361 rect.width = 1;
1362 rect.height = 1;
1363
1364 if (!pad->priv->toolbar_timeout && !gtk_widget_intersect (GTK_WIDGET (pad), &rect, NULL))
1365 pad->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
1366
1367 g_signal_handlers_unblock_matched (pad, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) xpad_pad_leave_notify_event, NULL);
1368}
1369
1370static gboolean
1371xpad_pad_button_press_event (XpadPad *pad,
1372 GdkEventButton *event)
1373{
1374 if (event->type == GDK_BUTTON_PRESS)
1375 {
1376 switch (event->button)
1377 {
1378 case 1:
1379 if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK)
1380 {
1381 gtk_window_begin_move_drag (GTK_WINDOW (pad), (gint) event->button, (gint) event->x_root, (gint) event->y_root, event->time);
1382 return TRUE;
1383 }
1384 break;
1385
1386 case 3:
1387 if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK)
1388 {
1389 GdkWindowEdge edge;
1390
1391 if (gtk_widget_get_direction (GTK_WIDGET (pad)) == GTK_TEXT_DIR_LTR)
1392 edge = GDK_WINDOW_EDGE_SOUTH_EAST;
1393 else
1394 edge = GDK_WINDOW_EDGE_SOUTH_WEST;
1395
1396 gtk_window_begin_resize_drag (GTK_WINDOW (pad), edge, (gint) event->button, (gint) event->x_root, (gint) event->y_root, event->time);
1397 }
1398 else
1399 {
1400 xpad_pad_popup (pad, event);
1401 }
1402 return TRUE;
1403 }
1404 }
1405
1406 return FALSE;
1407}
1408
1409static void
1410xpad_pad_notify_has_scrollbar (XpadPad *pad)
1411{
1412 gboolean has_scrollbar;
1413 g_object_get (pad->priv->settings, "has-scrollbar", &has_scrollbar, NULL);
1414
1415 /* Update pad menu with the new status */
1416 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-scrollbar");
1417 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), has_scrollbar);
1418
1419 if (has_scrollbar)
1420 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pad->priv->scrollbar),
1421 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1422 else
1423 {
1424 GtkAdjustment *v, *h;
1425
1426 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (pad->priv->scrollbar),
1427 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
1428
1429 /* now we need to adjust view so that user can see whole pad */
1430 h = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (pad->priv->scrollbar));
1431 v = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (pad->priv->scrollbar));
1432
1433 gtk_adjustment_set_value (h, 0);
1434 gtk_adjustment_set_value (v, 0);
1435 }
1436}
1437
1438static void
1439xpad_pad_notify_has_decorations (XpadPad *pad)
1440{
1441 GtkWidget *pad_widget = GTK_WIDGET (pad);
1442 GtkWindow *pad_window = GTK_WINDOW (pad);
1443 gboolean decorations;
1444 g_object_get (pad->priv->settings, "has-decorations", &decorations, NULL);
1445
1446 /* Update pad menu with the new status */
1447 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-decorations");
1448 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), decorations);
1449
1450 /*
1451 * There are two modes of operation: a normal mode and a 'stealth' mode.
1452 * If decorations are disabled, we also don't show up in the taskbar or pager.
1453 */
1454 gtk_window_set_decorated (pad_window, decorations);
1455 gtk_window_set_skip_taskbar_hint (pad_window, !decorations);
1456 gtk_window_set_skip_pager_hint (pad_window, !decorations);
1457
1458 /*
1459 * reshow_with_initial_size() seems to set the window back to a never-shown state.
1460 * This is good, as some WMs don't like us changing the above parameters mid-run,
1461 * even if we do a hide/show cycle.
1462 */
1463 gtk_window_set_default_size (pad_window, (gint) pad->priv->width, (gint) pad->priv->height);
1464 gtk_widget_hide (pad_widget);
1465 gtk_widget_unrealize (pad_widget);
1466 gtk_widget_show (pad_widget);
1467}
1468
1469static void
1470xpad_pad_notify_has_toolbar (XpadPad *pad)
1471{
1472 gboolean has_toolbar, autohide_toolbar;
1473 g_object_get (pad->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
1474
1475 /* Update pad menu with the new status */
1476 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-toolbar");
1477 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), has_toolbar);
1478 menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-autohide-toolbar");
1479 gtk_widget_set_sensitive (menu_item, has_toolbar);
1480
1481 if (has_toolbar && !autohide_toolbar)
1482 xpad_pad_show_toolbar (pad);
1483 else
1484 xpad_pad_hide_toolbar (pad);
1485}
1486
1487static void
1488xpad_pad_notify_autohide_toolbar (XpadPad *pad)
1489{
1490 gboolean autohide_toolbar;
1491 g_object_get (pad->priv->settings, "autohide-toolbar", &autohide_toolbar, NULL);
1492
1493 /* Update pad menu with the new status */
1494 GtkWidget *menu_item = g_object_get_data (G_OBJECT (pad->priv->menu), "has-autohide-toolbar");
1495 gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), autohide_toolbar);
1496
1497 if (autohide_toolbar)
1498 {
1499 /* Likely not to be in pad when turning setting on */
1500 if (!pad->priv->toolbar_timeout)
1501 pad->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
1502 }
1503 else
1504 {
1505 gboolean has_toolbar;
1506 g_object_get (pad->priv->settings, "has-toolbar", &has_toolbar, NULL);
1507
1508 if (has_toolbar)
1509 xpad_pad_show_toolbar(pad);
1510 }
1511}
1512
1513static void
1514xpad_pad_clear (XpadPad *pad)
1515{
1516 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
1517 gtk_text_buffer_set_text (buffer, "", -1);
1518}
1519
1520static gboolean
1521xpad_pad_enter_notify_event (GtkWidget *pad,
1522 GdkEventCrossing *event)
1523{
1524 gboolean has_toolbar, autohide_toolbar;
1525 g_object_get (XPAD_PAD (pad)->priv->settings, "has-toolbar", &has_toolbar, "autohide-toolbar", &autohide_toolbar, NULL);
1526
1527 if (has_toolbar && autohide_toolbar &&
1528 event->detail != GDK_NOTIFY_INFERIOR &&
1529 event->mode == GDK_CROSSING_NORMAL)
1530 {
1531 XPAD_PAD (pad)->priv->toolbar_timeout = 0;
1532 xpad_pad_show_toolbar (XPAD_PAD (pad));
1533 }
1534
1535 return FALSE;
1536}
1537
1538static void xpad_pad_constructed (GObject *object)
1539{
1540 XpadPad *pad = XPAD_PAD (object);
1541
1542 gboolean decorations;
1543 GtkBox *vbox;
1544
1545 g_object_get (pad->priv->settings,
1546 "width", &pad->priv->width,
1547 "height", &pad->priv->height,
1548 "autostart-sticky", &pad->priv->sticky, NULL);
1549
1550 GtkWindow *pad_window = GTK_WINDOW (pad);
1551
1552 pad->priv->textview = GTK_WIDGET (XPAD_TEXT_VIEW (xpad_text_view_new (pad->priv->settings, pad)));
1553
1554 pad->priv->scrollbar = GTK_WIDGET (g_object_new (GTK_TYPE_SCROLLED_WINDOW,
1555 "hadjustment", NULL,
1556 "hscrollbar-policy", GTK_POLICY_NEVER,
1557 "shadow-type", GTK_SHADOW_NONE,
1558 "vadjustment", NULL,
1559 "vscrollbar-policy", GTK_POLICY_NEVER,
1560 "child", pad->priv->textview,
1561 NULL));
1562
1563 pad->priv->toolbar = GTK_WIDGET (xpad_toolbar_new (pad));
1564
1565 pad->priv->accel_group = gtk_accel_group_new ();
1566 gtk_window_add_accel_group (pad_window, pad->priv->accel_group);
1567 pad->priv->menu = menu_get_popup_no_highlight (pad, pad->priv->accel_group);
1568 pad->priv->highlight_menu = menu_get_popup_highlight (pad, pad->priv->accel_group);
1569 gtk_accel_group_connect (pad->priv->accel_group, GDK_KEY_Q, GDK_CONTROL_MASK, 0, g_cclosure_new_swap (G_CALLBACK (xpad_app_quit), pad, NULL));
1570
1571 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 0));
1572 gtk_box_set_homogeneous (vbox, FALSE);
1573 gtk_box_pack_start (vbox, pad->priv->scrollbar, TRUE, TRUE, 0);
1574 gtk_box_pack_start (vbox, pad->priv->toolbar, FALSE, FALSE, 0);
1575
1576 gtk_container_child_set (GTK_CONTAINER (vbox), pad->priv->toolbar, "expand", FALSE, NULL);
1577
1578 g_object_get (pad->priv->settings, "has-decorations", &decorations, NULL);
1579 gtk_window_set_decorated (pad_window, decorations);
1580 gtk_window_set_default_size (pad_window, (gint) pad->priv->width, (gint) pad->priv->height);
1581 gtk_window_set_gravity (pad_window, GDK_GRAVITY_STATIC); /* static gravity makes saving pad x,y work */
1582 gtk_window_set_skip_pager_hint (pad_window, decorations);
1583 gtk_window_set_skip_taskbar_hint (pad_window, !decorations);
1584 gtk_window_set_position (pad_window, GTK_WIN_POS_MOUSE);
1585
1586 g_object_set (G_OBJECT (pad), "child", vbox, NULL);
1587
1588 xpad_pad_notify_has_scrollbar (pad);
1589 xpad_pad_notify_has_selection (pad);
1590 xpad_pad_notify_clipboard_owner_changed (pad);
1591 xpad_pad_notify_undo_redo_changed (pad);
1592
1593 pad->priv->clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1594
1595 if (pad->priv->sticky)
1596 gtk_window_stick (pad_window);
1597 else
1598 gtk_window_unstick (pad_window);
1599
1600 xpad_pad_sync_title (pad);
1601
1602 gtk_widget_show_all (GTK_WIDGET (vbox));
1603
1604 gtk_widget_hide (pad->priv->toolbar);
1605 xpad_pad_notify_has_toolbar (pad);
1606
1607 /* Set up signals */
1608 gtk_widget_add_events (GTK_WIDGET (pad), GDK_BUTTON_PRESS_MASK | GDK_PROPERTY_CHANGE_MASK);
1609 gtk_widget_add_events (pad->priv->toolbar, GDK_ALL_EVENTS_MASK);
1610 g_signal_connect_swapped (pad->priv->textview, "button-press-event", G_CALLBACK (xpad_pad_button_press_event), pad);
1611 g_signal_connect_swapped (pad->priv->textview, "popup-menu", G_CALLBACK (xpad_pad_popup_menu), pad);
1612 g_signal_connect_swapped (pad->priv->toolbar, "size-allocate", G_CALLBACK (xpad_pad_toolbar_size_allocate), pad);
1613 g_signal_connect (pad, "button-press-event", G_CALLBACK (xpad_pad_button_press_event), NULL);
1614 g_signal_connect (pad, "configure-event", G_CALLBACK (xpad_pad_configure_event), NULL);
1615 g_signal_connect (pad, "delete-event", G_CALLBACK (xpad_pad_delete_event), NULL);
1616 g_signal_connect (pad, "popup-menu", G_CALLBACK (xpad_pad_popup_menu), NULL);
1617 g_signal_connect (pad, "show", G_CALLBACK (xpad_pad_show), NULL);
1618 g_signal_connect_swapped (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)), "changed", G_CALLBACK (xpad_pad_text_changed), pad);
1619
1620 g_signal_connect (pad, "enter-notify-event", G_CALLBACK (xpad_pad_enter_notify_event), NULL);
1621 g_signal_connect (pad, "leave-notify-event", G_CALLBACK (xpad_pad_leave_notify_event), NULL);
1622
1623 g_signal_connect_swapped (pad->priv->settings, "notify::has-decorations", G_CALLBACK (xpad_pad_notify_has_decorations), pad);
1624 g_signal_connect_swapped (pad->priv->settings, "notify::has-toolbar", G_CALLBACK (xpad_pad_notify_has_toolbar), pad);
1625 g_signal_connect_swapped (pad->priv->settings, "notify::autohide-toolbar", G_CALLBACK (xpad_pad_notify_autohide_toolbar), pad);
1626 g_signal_connect_swapped (pad->priv->settings, "notify::has-scrollbar", G_CALLBACK (xpad_pad_notify_has_scrollbar), pad);
1627 g_signal_connect_swapped (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)), "notify::has-selection", G_CALLBACK (xpad_pad_notify_has_selection), pad);
1628 g_signal_connect_swapped (pad->priv->clipboard, "owner-change", G_CALLBACK (xpad_pad_notify_clipboard_owner_changed), pad);
1629
1630 g_signal_connect_swapped (pad->priv->toolbar, "activate-new", G_CALLBACK (xpad_pad_spawn), pad);
1631 g_signal_connect_swapped (pad->priv->toolbar, "activate-clear", G_CALLBACK (xpad_pad_clear), pad);
1632 g_signal_connect_swapped (pad->priv->toolbar, "activate-close", G_CALLBACK (xpad_pad_close), pad);
1633 g_signal_connect_swapped (pad->priv->toolbar, "activate-undo", G_CALLBACK (xpad_pad_undo), pad);
1634 g_signal_connect_swapped (pad->priv->toolbar, "activate-redo", G_CALLBACK (xpad_pad_redo), pad);
1635 g_signal_connect_swapped (pad->priv->toolbar, "activate-cut", G_CALLBACK (xpad_pad_cut), pad);
1636 g_signal_connect_swapped (pad->priv->toolbar, "activate-copy", G_CALLBACK (xpad_pad_copy), pad);
1637 g_signal_connect_swapped (pad->priv->toolbar, "activate-paste", G_CALLBACK (xpad_pad_paste), pad);
1638 g_signal_connect_swapped (pad->priv->toolbar, "activate-delete", G_CALLBACK (xpad_pad_delete), pad);
1639 g_signal_connect_swapped (pad->priv->toolbar, "activate-properties", G_CALLBACK (xpad_pad_open_properties), pad);
1640 g_signal_connect_swapped (pad->priv->toolbar, "activate-preferences", G_CALLBACK (xpad_pad_open_preferences), pad);
1641 g_signal_connect_swapped (pad->priv->toolbar, "activate-quit", G_CALLBACK (xpad_pad_close_all), pad);
1642
1643 g_signal_connect_swapped (pad->priv->toolbar, "popup", G_CALLBACK (menu_popup), pad);
1644 g_signal_connect_swapped (pad->priv->toolbar, "popdown", G_CALLBACK (menu_popdown), pad);
1645
1646 g_signal_connect_swapped (pad->priv->menu, "deactivate", G_CALLBACK (menu_popdown), pad);
1647 g_signal_connect_swapped (pad->priv->highlight_menu, "deactivate", G_CALLBACK (menu_popdown), pad);
1648}
1649
1650static void
1651xpad_pad_dispose (GObject *object)
1652{
1653 XpadPad *pad = XPAD_PAD (object);
1654
1655 if (pad->priv->group) {
1656 g_object_unref(pad->priv->group);
1657 pad->priv->group = NULL;
1658 }
1659
1660 if (GTK_IS_WIDGET(pad->priv->menu)) {
1661 gtk_widget_destroy (pad->priv->menu);
1662 pad->priv->menu = NULL;
1663 }
1664
1665 if (GTK_IS_WIDGET(pad->priv->highlight_menu)) {
1666 gtk_widget_destroy (pad->priv->highlight_menu);
1667 pad->priv->highlight_menu = NULL;
1668 }
1669
1670 if (XPAD_IS_PAD_PROPERTIES (pad->priv->properties)) {
1671 gtk_widget_destroy (pad->priv->properties);
1672 pad->priv->properties = NULL;
1673 }
1674
1675 gtk_clipboard_clear (pad->priv->clipboard);
1676
1677 /* For some reason the toolbar handler does not get automatically disconnected (or not at the right moment), leading to errors after deleting a pad. This manual disconnect prevents this error. */
1678 if (XPAD_IS_TOOLBAR (pad->priv->toolbar)) {
1679 g_signal_handlers_disconnect_matched (pad->priv->toolbar, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, pad);
1680 gtk_widget_destroy(pad->priv->toolbar);
1681 pad->priv->toolbar = NULL;
1682 }
1683
1684 G_OBJECT_CLASS (xpad_pad_parent_class)->dispose (object);
1685}
1686
1687static void
1688xpad_pad_finalize (GObject *object)
1689{
1690 XpadPad *pad = XPAD_PAD (object);
1691
1692 if (pad->priv->settings) {
1693 g_signal_handlers_disconnect_matched (pad->priv->settings, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, pad);
1694 g_object_unref(pad->priv->settings);
1695 pad->priv->settings = NULL;
1696 }
1697
1698 g_free (pad->priv->infoname);
1699 g_free (pad->priv->contentname);
1700
1701 G_OBJECT_CLASS (xpad_pad_parent_class)->finalize (object);
1702}
1703
1704void
1705xpad_pad_notify_has_selection (XpadPad *pad)
1706{
1707 g_return_if_fail (pad);
1708
1709 GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
1710 gboolean has_selection = gtk_text_buffer_get_has_selection (buffer);
1711
1712 XpadToolbar *toolbar = XPAD_TOOLBAR (pad->priv->toolbar);
1713 if (toolbar == NULL)
1714 return;
1715
1716 xpad_toolbar_enable_cut_button (toolbar, has_selection);
1717 xpad_toolbar_enable_copy_button (toolbar, has_selection);
1718}
1719
1720void
1721xpad_pad_notify_clipboard_owner_changed (XpadPad *pad)
1722{
1723 g_return_if_fail (pad);
1724
1725 /* safe cast to toolbar */
1726 if (XPAD_IS_TOOLBAR (pad->priv->toolbar)) {
1727 XpadToolbar *toolbar = XPAD_TOOLBAR (pad->priv->toolbar);
1728 g_return_if_fail (toolbar);
1729
1730 GtkClipboard *clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1731 xpad_toolbar_enable_paste_button (toolbar, gtk_clipboard_wait_is_text_available (clipboard));
1732 }
1733}
1734
1735void
1736xpad_pad_notify_undo_redo_changed (XpadPad *pad)
1737{
1738 g_return_if_fail (pad);
1739
1740 XpadTextBuffer *buffer = NULL;
1741 buffer = XPAD_TEXT_BUFFER (gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview)));
1742 g_return_if_fail (buffer);
1743
1744 XpadToolbar *toolbar = NULL;
1745 toolbar = XPAD_TOOLBAR (pad->priv->toolbar);
1746 g_return_if_fail (toolbar);
1747
1748 xpad_toolbar_enable_undo_button (toolbar, xpad_text_buffer_undo_available (buffer));
1749 xpad_toolbar_enable_redo_button (toolbar, xpad_text_buffer_redo_available (buffer));
1750}
1751
1752void
1753xpad_pad_close (XpadPad *pad)
1754{
1755 gtk_widget_hide (GTK_WIDGET (pad));
1756
1757 /*
1758 * If no tray and this is the last pad, we don't want to record this
1759 * pad as closed, we want to start with just this pad next open. So
1760 * quit before we record.
1761 */
1762 if (!xpad_tray_is_open () &&
1763 xpad_pad_group_num_visible_pads (pad->priv->group) == 0)
1764 {
1765 xpad_app_quit ();
1766 return;
1767 }
1768
1769 if (pad->priv->properties)
1770 gtk_widget_destroy (pad->priv->properties);
1771
1772 xpad_pad_save_info (pad);
1773
1774 g_signal_emit (pad, signals[CLOSED], 0);
1775}
1776
1777void
1778xpad_pad_toggle(XpadPad *pad)
1779{
1780 if (gtk_widget_get_visible (GTK_WIDGET(pad)))
1781 xpad_pad_close (pad);
1782 else
1783 gtk_widget_show (GTK_WIDGET (pad));
1784}
1785
1750void xpad_pad_append_pad_titles_to_menu (GtkWidget *menu)1786void xpad_pad_append_pad_titles_to_menu (GtkWidget *menu)
1751{1787{
1752 GSList *pads, *l;1788 GSList *pads, *l;
@@ -1782,114 +1818,75 @@
1782 g_slist_free (pads);1818 g_slist_free (pads);
1783}1819}
17841820
1785static GtkWidget *
1786menu_get_popup_highlight (XpadPad *pad, GtkAccelGroup *accel_group)
1787{
1788 GtkWidget *menu, *item;
1789
1790 menu = gtk_menu_new ();
1791 gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
1792
1793 MENU_ADD (_("Cu_t"), "edit-cut", 0, 0, xpad_pad_cut);
1794 MENU_ADD (_("_Copy"), "edit-copy", 0, 0, xpad_pad_copy);
1795 MENU_ADD (_("_Paste"), "edit-paste", 0, 0, xpad_pad_paste);
1796 g_object_set_data (G_OBJECT (menu), "paste", item);
1797 MENU_ADD_SEP ();
1798 MENU_ADD (_("_Bold"), "format-text-bold", GDK_KEY_b, GDK_CONTROL_MASK, menu_bold);
1799 MENU_ADD (_("_Italic"), "format-text-italic", GDK_KEY_i, GDK_CONTROL_MASK, menu_italic);
1800 MENU_ADD (_("_Underline"), "format-text-underline", GDK_KEY_u, GDK_CONTROL_MASK, menu_underline);
1801 MENU_ADD (_("_Strikethrough"), "format-text-strikethrough", 0, 0, menu_strikethrough);
1802
1803 gtk_widget_show_all (menu);
1804
1805 return menu;
1806}
1807
1808static void
1809menu_prep_popup_highlight (XpadPad *pad, GtkWidget *menu)
1810{
1811 /* A dirty way to silence the compiler for these unused variables. */
1812 (void) pad;
1813
1814 GtkWidget *item;
1815 GtkClipboard *clipboard;
1816
1817 clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
1818
1819 item = g_object_get_data (G_OBJECT (menu), "paste");
1820 if (item)
1821 gtk_widget_set_sensitive (item, gtk_clipboard_wait_is_text_available (clipboard));
1822}
1823
1824static void
1825menu_popup (XpadPad *pad)
1826{
1827 g_signal_handlers_block_matched (pad, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) xpad_pad_leave_notify_event, NULL);
1828 pad->priv->toolbar_timeout = 0;
1829}
1830
1831static void
1832menu_popdown (XpadPad *pad)
1833{
1834 cairo_rectangle_int_t rect;
1835
1836 /* We must check if we disabled off of pad and start the timeout if so. */
1837 rect.x = 10;
1838 rect.y = 10;
1839 rect.width = 1;
1840 rect.height = 1;
1841
1842 if (!pad->priv->toolbar_timeout && !gtk_widget_intersect (GTK_WIDGET (pad), &rect, NULL))
1843 pad->priv->toolbar_timeout = g_timeout_add (1000, (GSourceFunc) toolbar_timeout, pad);
1844
1845 g_signal_handlers_unblock_matched (pad, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, (gpointer) xpad_pad_leave_notify_event, NULL);
1846}
1847
1848static void
1849xpad_pad_popup (XpadPad *pad, GdkEventButton *event)
1850{
1851 GtkTextBuffer *buffer;
1852 GtkWidget *menu;
1853
1854 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (pad->priv->textview));
1855
1856 if (gtk_text_buffer_get_selection_bounds (buffer, NULL, NULL))
1857 {
1858 menu = pad->priv->highlight_menu;
1859 menu_prep_popup_highlight (pad, menu);
1860 }
1861 else
1862 {
1863 menu = pad->priv->menu;
1864 menu_prep_popup_no_highlight (pad, menu);
1865 }
1866
1867 if (!menu)
1868 return;
1869
1870 menu_popup (pad);
1871
1872 if (event)
1873 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, event->button, event->time);
1874 else
1875 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time ());
1876}
1877
1878/* These functions below are used to reduce the amounts of writes, hence improve the performance. */1821/* These functions below are used to reduce the amounts of writes, hence improve the performance. */
1879void xpad_pad_save_content_delayed (XpadPad *pad)1822void xpad_pad_save_content_delayed (XpadPad *pad)
1880{1823{
1881 pad->priv->unsaved_content = TRUE;1824 pad->priv->unsaved_content = TRUE;
1882 xpad_periodic_save_content_delayed (pad);1825 xpad_periodic_save_content_delayed (pad);
1883}1826}
1827
1884void xpad_pad_save_info_delayed (XpadPad *pad)1828void xpad_pad_save_info_delayed (XpadPad *pad)
1885{1829{
1886 pad->priv->unsaved_info = TRUE;1830 pad->priv->unsaved_info = TRUE;
1887 xpad_periodic_save_info_delayed (pad);1831 xpad_periodic_save_info_delayed (pad);
1888}1832}
1833
1889void xpad_pad_save_unsaved (XpadPad *pad)1834void xpad_pad_save_unsaved (XpadPad *pad)
1890{1835{
1891 if (pad->priv->unsaved_content)1836 if (pad->priv->unsaved_content)
1892 xpad_pad_save_content (pad);1837 xpad_pad_save_content (pad);
1893 if (pad->priv->unsaved_info)1838 if (pad->priv->unsaved_info)
1894 xpad_pad_save_info (pad);1839 xpad_pad_save_info (pad);
1840}
1841
1842/* Class pad - constructor */
1843static void
1844xpad_pad_class_init (XpadPadClass *klass)
1845{
1846 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1847
1848 gobject_class->constructed = xpad_pad_constructed;
1849 gobject_class->set_property = xpad_pad_set_property;
1850 gobject_class->get_property = xpad_pad_get_property;
1851 gobject_class->dispose = xpad_pad_dispose;
1852 gobject_class->finalize = xpad_pad_finalize;
1853
1854 signals[CLOSED] =
1855 g_signal_new ("closed",
1856 G_OBJECT_CLASS_TYPE (gobject_class),
1857 G_SIGNAL_RUN_FIRST,
1858 G_STRUCT_OFFSET (XpadPadClass, closed),
1859 NULL, NULL,
1860 g_cclosure_marshal_VOID__VOID,
1861 G_TYPE_NONE,
1862 0);
1863
1864 /* Properties */
1865 obj_prop[PROP_GROUP] = g_param_spec_pointer ("group", "Pad group", "Pad group for this pad", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1866 obj_prop[PROP_SETTINGS] = g_param_spec_pointer ("settings", "Xpad settings", "Xpad global settings", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
1867
1868 g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_prop);
1869}
1870
1871/* Class pad - initializer */
1872static void
1873xpad_pad_init (XpadPad *pad)
1874{
1875 pad->priv = xpad_pad_get_instance_private (pad);
1876
1877 pad->priv->x = 0;
1878 pad->priv->y = 0;
1879 pad->priv->location_valid = FALSE;
1880 pad->priv->infoname = NULL;
1881 pad->priv->contentname = NULL;
1882 pad->priv->textview = NULL;
1883 pad->priv->scrollbar = NULL;
1884 pad->priv->toolbar = NULL;
1885 pad->priv->toolbar_timeout = 0;
1886 pad->priv->toolbar_height = 0;
1887 pad->priv->toolbar_expanded = FALSE;
1888 pad->priv->toolbar_pad_resized = TRUE;
1889 pad->priv->properties = NULL;
1890 pad->priv->unsaved_content = FALSE;
1891 pad->priv->unsaved_info = FALSE;
1895}1892}
18961893
=== modified file 'src/xpad-periodic.c'
--- src/xpad-periodic.c 2014-06-19 09:08:49 +0000
+++ src/xpad-periodic.c 2014-09-08 13:22:52 +0000
@@ -20,246 +20,269 @@
20*/20*/
2121
22#include "../config.h"22#include "../config.h"
23
23#include "xpad-periodic.h"24#include "xpad-periodic.h"
24#include <glib/gi18n.h>25
25#include <stdlib.h>26#include <stdlib.h>
26#include <string.h>27#include <string.h>
2728
29#include <glib/gi18n.h>
30
28#ifdef SHOW_DEBUG31#ifdef SHOW_DEBUG
29# define G_PRINT_DBG g_print32# define G_PRINT_DBG g_print
30#else33#else
31# define G_PRINT_DBG gprint_ignore34# define G_PRINT_DBG gprint_ignore
32#endif35#endif
3336
34#define TIMEOUT_SECONDS 437#define TIMEOUT_SECONDS 4
3538
36struct sigref_ {39struct sigref_ {
37 const char * signame;40 const char *signame;
38 XpadPeriodicFunc func_ptr;41 XpadPeriodicFunc func_ptr;
39 gpointer data;42 gpointer data;
40};43};
4144
42typedef struct sigref_ Xpadsigref;45typedef struct sigref_ Xpadsigref;
4346
44typedef struct {47typedef struct {
45 /************************48 /************************
46 count = a clock tick count49 count = a clock tick count
47 after_id = the timeout id50 after_id = the timeout id
48 ************************/51 ************************/
49 int count;52 int count;
50 int after_id;53 int after_id;
5154
52 /************************55 /************************
53 template = a list of signal names and function pointers56 template = a list of signal names and function pointers
54 template_len = the length of 'template'57 template_len = the length of 'template'
55 sigs = a list of signal names, function pointers and data58 sigs = a list of signal names, function pointers and data
56 sigs_len = the length of 'sigs'59 sigs_len = the length of 'sigs'
57 ************************/60 ************************/
58 Xpadsigref * template;61 Xpadsigref *template;
59 int template_len;62 int template_len;
60 Xpadsigref * sigs;63 Xpadsigref *sigs;
61 int sigs_len;64 int sigs_len;
62} XpadPeriodic;65} XpadPeriodic;
6366
64
65/* prototypes */
66static gint xppd_intercept (gpointer);
67static gint gprint_ignore(const char *, ...);67static gint gprint_ignore(const char *, ...);
68static void xpad_periodic_signal (const char * cbname, void * xpad_pad);
69static void xpad_periodic_error_exit (const char *, ...);
70
71static gboolean str_equal (const char *, const char *);
7268
73/* global variables */69/* global variables */
74static XpadPeriodic xpptr [1];70static XpadPeriodic xpptr [1];
7571
76/* Functions start here */72/* Functions start here */
7773
78gboolean xpad_periodic_init (void)74void
79{75xpad_periodic_close (void)
80 memset(xpptr, 0, sizeof(*xpptr));76{
81 xpptr->after_id = (gint) g_timeout_add_seconds(TIMEOUT_SECONDS, xppd_intercept, xpptr);77 if (xpptr->after_id) { g_source_remove((guint) xpptr->after_id); }
8278 /* Free the signal references memory. */
83 /* Allocate space for the signal references. */79 g_free(xpptr->template);
84 int tlen = xpptr->template_len = 5;80 g_free(xpptr->sigs);
85 int slen = xpptr->sigs_len = 20;81 /* Signal that this structure is now cleared. */
86 xpptr->template = g_malloc0((gsize) tlen * sizeof(Xpadsigref));82 memset(xpptr, 0, sizeof(*xpptr));
87 xpptr->sigs = g_malloc0((gsize) slen * sizeof(Xpadsigref));83}
8884
89 return TRUE;85 /************************
90}86 xppd_intercept - intercepts a timer tick
9187
92void xpad_periodic_close (void)88 This function intercepts a timer tick and iterates
93{89 over the signal references. Any signal references that
94 if (xpptr->after_id) { g_source_remove((guint) xpptr->after_id); }90 are fully stocked with signal names, function pointers
95 /* Free the signal references memory. */91 and data pointers are invoked.
96 g_free(xpptr->template);92
97 g_free(xpptr->sigs);93 IOW (In other words), the function pointer is called with the
98 /* Signal that this structure is now cleared. */94 right data pointer.
99 memset(xpptr, 0, sizeof(*xpptr));95 ************************/
100}96gint
10197xppd_intercept (gpointer cdata)
102/************************
103xppd_intercept - intercepts a timer tick
104
105 This function intercepts a timer tick and iterates
106 over the signal references. Any signal references that
107 are fully stocked with signal names, function pointers
108 and data pointers are invoked.
109
110 IOW (In other words), the function pointer is called with the
111 right data pointer.
112************************/
113gint xppd_intercept (gpointer cdata)
114{98{
115 /* A dirty way to silence the compiler for these unused variables. */99 /* A dirty way to silence the compiler for these unused variables. */
116 (void) cdata;100 (void) cdata;
117101
118 int cnt=0;102 int cnt=0;
119 XpadPeriodicFunc fnptr=0;103 XpadPeriodicFunc fnptr=0;
120 xpptr->count++; /* increment tick count */104 xpptr->count++; /* increment tick count */
121105
122 G_PRINT_DBG("xppd tick: %4d\n", xpptr->count);106 G_PRINT_DBG ("xppd tick: %4d\n", xpptr->count);
123107
124 for (cnt = 0; cnt < xpptr->sigs_len; ++cnt) {108 for (cnt = 0; cnt < xpptr->sigs_len; ++cnt)
125 Xpadsigref * sig_item = xpptr->sigs + cnt;109 {
126 if (sig_item->signame && sig_item->func_ptr && sig_item->data) {110 Xpadsigref * sig_item = xpptr->sigs + cnt;
127 fnptr = sig_item->func_ptr;111 if (sig_item->signame && sig_item->func_ptr && sig_item->data)
128 (*fnptr)(sig_item->data);112 {
129 G_PRINT_DBG("invoked %s : %p : %p\n", sig_item->signame,113 fnptr = sig_item->func_ptr;
130 sig_item->func_ptr, sig_item->data);114 (*fnptr)(sig_item->data);
131 memset(sig_item, 0, sizeof(*sig_item));115 G_PRINT_DBG ("invoked %s : %p : %p\n", sig_item->signame,
132 }116 sig_item->func_ptr, sig_item->data);
133 }117 memset(sig_item, 0, sizeof(*sig_item));
134118 }
135 return TRUE;119 }
136}120
137121 return TRUE;
138/************************122}
139 Xpad_periodic_set_callback():123
140 This function prepares a callback function to be invoked124 /************************
141 for an event name such as "save-content" or "save-info".125 Xpad_periodic_set_callback():
142126 This function prepares a callback function to be invoked
143 cbname : event name (or callback function name)127 for an event name such as "save-content" or "save-info".
144 func : function address128
145129 cbname : event name (or callback function name)
146 Returns true if a callback was registered.130 func : function address
147************************/131
148gboolean xpad_periodic_set_callback (132 Returns true if a callback was registered.
149 const char * cbname,133 ************************/
150 XpadPeriodicFunc func)134gboolean
151{135xpad_periodic_set_callback (const char * cbname,
152 int index = 0;136 XpadPeriodicFunc func)
153 gboolean isdone=FALSE;137{
154 if (0 == func) { return FALSE; }138 int index = 0;
155 if (0 == cbname || 0==*cbname) { return FALSE; }139 gboolean isdone=FALSE;
156140 if (0 == func) { return FALSE; }
157 /* Find an open slot for signal (callback) references and141 if (0 == cbname || 0==*cbname) { return FALSE; }
158 insert this one. */142
159 for (index = 0; index < xpptr->template_len; ++index) {143 /* Find an open slot for signal (callback) references and
160 /* Store a pointer to the current signal item. */144 insert this one. */
161 Xpadsigref * sig_item = xpptr->template + index;145 for (index = 0; index < xpptr->template_len; ++index)
162146 {
163 /* If it's empty, set it. */147 /* Store a pointer to the current signal item. */
164 if (0 == sig_item->signame) {148 Xpadsigref * sig_item = xpptr->template + index;
165 sig_item->signame = cbname;149
166 sig_item->func_ptr = func;150 /* If it's empty, set it. */
167 isdone = TRUE;151 if (0 == sig_item->signame)
168 break;152 {
169 }153 sig_item->signame = cbname;
170 }154 sig_item->func_ptr = func;
171155 isdone = TRUE;
172 if (! isdone) {156 break;
173 g_print("Failed to install signal callback: %s\n", cbname);157 }
174 exit(1);158 }
175 }159
176160 if (! isdone)
177 return isdone;161 {
178}162 g_print ("Failed to install signal callback: %s\n", cbname);
179163 exit (1);
180void xpad_periodic_save_info_delayed (void * xpad_pad)164 }
181{165
182 xpad_periodic_signal("save-info", xpad_pad);166 return isdone;
183}167}
184168
185void xpad_periodic_save_content_delayed (void * xpad_pad)169gboolean
186{170xpad_periodic_init (void)
187 xpad_periodic_signal("save-content", xpad_pad);171{
188}172 memset(xpptr, 0, sizeof(*xpptr));
189173 xpptr->after_id = (gint) g_timeout_add_seconds(TIMEOUT_SECONDS, xppd_intercept, xpptr);
190static void xpad_periodic_signal (const char * cbname, void * xpad_pad) {174
191 int isdone = 0;175 /* Allocate space for the signal references. */
192 int tnx=0, snx=0;176 int tlen = xpptr->template_len = 5;
193 XpadPeriodicFunc func_ptr = 0;177 int slen = xpptr->sigs_len = 20;
194 Xpadsigref * sig_item = 0;178 xpptr->template = g_malloc0((gsize) tlen * sizeof(Xpadsigref));
195179 xpptr->sigs = g_malloc0((gsize) slen * sizeof(Xpadsigref));
196 if (0 == cbname || 0==*cbname) { return; }180
197 if (0 == xpad_pad) { return; }181 return TRUE;
198182}
199 /* Get the callback function address */183
200 for (tnx = 0; tnx < xpptr->template_len; ++tnx) {184static void
201 if (str_equal(xpptr->template[tnx].signame, cbname)) {185xpad_periodic_error_exit (const char * fmt, ...)
202 func_ptr = xpptr->template[tnx].func_ptr;186{
203 break;187 va_list app;
204 }188 va_start (app, fmt);
205 }189 g_print (fmt, app);
206190 va_end (app);
207 /* If there is no callback address, we can't continue. */191 exit (1);
208 if (! func_ptr) {192}
209 xpad_periodic_error_exit("Can't find signal function address: %s\n", cbname);193
210 }194static void
211195xpad_periodic_signal (const char * cbname,
212 /* Check that this event is not already present. 196 void * xpad_pad)
213 If it is present, don't do anything more. */197{
214 for (snx = 0; snx < xpptr->sigs_len; ++snx) {198 int isdone = 0;
215 sig_item = xpptr->sigs + snx;199 int tnx=0, snx=0;
216 if (str_equal(sig_item->signame,cbname) &&200 XpadPeriodicFunc func_ptr = 0;
217 (xpad_pad == sig_item->data)) {201 Xpadsigref * sig_item = 0;
218 G_PRINT_DBG("Already got signal: %s\n", cbname);202
219 return;203 if (0 == cbname || 0==*cbname) { return; }
220 }204 if (0 == xpad_pad) { return; }
221 }205
222206 /* Get the callback function address */
223 /* Find a suitable slot for the signal reference and set it. */207 for (tnx = 0; tnx < xpptr->template_len; ++tnx)
224 for (snx = 0; snx < xpptr->sigs_len; ++snx) {208 {
225 gint doadd = 0;209 if (str_equal (xpptr->template[tnx].signame, cbname))
226 sig_item = xpptr->sigs + snx;210 {
227211 func_ptr = xpptr->template[tnx].func_ptr;
228 doadd += (str_equal(sig_item->signame, cbname));212 break;
229 doadd += (0 == sig_item->signame);213 }
230214 }
231 if (doadd) {215
232 sig_item->signame = cbname;216 /* If there is no callback address, we can't continue. */
233 sig_item->func_ptr = func_ptr;217 if (! func_ptr)
234 sig_item->data = xpad_pad;218 {
235 isdone = TRUE;219 xpad_periodic_error_exit ("Can't find signal function address: %s\n", cbname);
236 break;220 }
237 }221
238 }222 /* Check that this event is not already present.
239223 If it is present, don't do anything more. */
240 if (! isdone) {224 for (snx = 0; snx < xpptr->sigs_len; ++snx)
241 xpad_periodic_error_exit("Could not schedule event: %s\n", cbname);225 {
242 }226 sig_item = xpptr->sigs + snx;
243}227 if (str_equal(sig_item->signame,cbname) &&
244228 (xpad_pad == sig_item->data))
245gboolean str_equal (const char * s1, const char * s2) {229 {
246 if (0 == s1 || 0==s2) { return FALSE; }230 G_PRINT_DBG ("Already got signal: %s\n", cbname);
247 if (s1 == s2) { return TRUE; }231 return;
248 return (0 == strcmp(s1, s2));232 }
249}233 }
250234
251gint gprint_ignore (const char * fmt, ...)235 /* Find a suitable slot for the signal reference and set it. */
236 for (snx = 0; snx < xpptr->sigs_len; ++snx)
237 {
238 gint doadd = 0;
239 sig_item = xpptr->sigs + snx;
240
241 doadd += (str_equal (sig_item->signame, cbname));
242 doadd += (0 == sig_item->signame);
243
244 if (doadd)
245 {
246 sig_item->signame = cbname;
247 sig_item->func_ptr = func_ptr;
248 sig_item->data = xpad_pad;
249 isdone = TRUE;
250 break;
251 }
252 }
253
254 if (! isdone)
255 {
256 xpad_periodic_error_exit ("Could not schedule event: %s\n", cbname);
257 }
258}
259
260void
261xpad_periodic_save_info_delayed (void * xpad_pad)
262{
263 xpad_periodic_signal ("save-info", xpad_pad);
264}
265
266void
267xpad_periodic_save_content_delayed (void * xpad_pad)
268{
269 xpad_periodic_signal ("save-content", xpad_pad);
270}
271
272gboolean
273str_equal (const char * s1,
274 const char * s2)
275{
276 if (0 == s1 || 0==s2) { return FALSE; }
277 if (s1 == s2) { return TRUE; }
278 return (0 == strcmp(s1, s2));
279}
280
281gint
282gprint_ignore (const char * fmt, ...)
252{283{
253 /* A dirty way to silence the compiler for these unused variables. */284 /* A dirty way to silence the compiler for these unused variables. */
254 (void) fmt;285 (void) fmt;
255286
256 return 0;287 return 0;
257}
258
259static void xpad_periodic_error_exit (const char * fmt, ...) {
260 va_list app;
261 va_start(app, fmt);
262 g_print(fmt, app);
263 va_end(app);
264 exit(1);
265}288}
266289
=== modified file 'src/xpad-periodic.h'
--- src/xpad-periodic.h 2014-06-19 09:08:49 +0000
+++ src/xpad-periodic.h 2014-09-08 13:22:52 +0000
@@ -19,11 +19,13 @@
1919
20*/20*/
2121
22#ifndef XPAD_PERIODIC_H22#ifndef __XPAD_PERIODIC_H__
23#define XPAD_PERIODIC_H23#define __XPAD_PERIODIC_H__
2424
25#include <glib.h>25#include <glib.h>
2626
27G_BEGIN_DECLS
28
27typedef void (*XpadPeriodicFunc)(void *);29typedef void (*XpadPeriodicFunc)(void *);
2830
29/* Callback function codes: save-content, save-info */31/* Callback function codes: save-content, save-info */
@@ -51,4 +53,6 @@
51void xpad_periodic_save_content_delayed (void * xpad_pad);53void xpad_periodic_save_content_delayed (void * xpad_pad);
52void xpad_periodic_save_info_delayed (void * xpad_pad);54void xpad_periodic_save_info_delayed (void * xpad_pad);
5355
54#endif /* XPAD_PERIODIC_H */56G_END_DECLS
57
58#endif /* __XPAD_PERIODIC_H__ */
5559
=== modified file 'src/xpad-preferences.c'
--- src/xpad-preferences.c 2014-07-20 16:36:07 +0000
+++ src/xpad-preferences.c 2014-09-08 13:22:52 +0000
@@ -20,10 +20,12 @@
20*/20*/
2121
22#include "../config.h"22#include "../config.h"
23
23#include "xpad-preferences.h"24#include "xpad-preferences.h"
25#include "xpad-app.h"
26
24#include <glib/gi18n.h>27#include <glib/gi18n.h>
25#include <gtk/gtk.h>28#include <gtk/gtk.h>
26#include "xpad-app.h"
2729
28struct XpadPreferencesPrivate 30struct XpadPreferencesPrivate
29{31{
@@ -36,12 +38,12 @@
36 GtkWidget *fontbutton;38 GtkWidget *fontbutton;
37 GtkWidget *colorcheck;39 GtkWidget *colorcheck;
38 GtkWidget *anticolorcheck;40 GtkWidget *anticolorcheck;
39 GtkWidget *colorbox; 41 GtkWidget *colorbox;
40 GtkWidget *textbutton;42 GtkWidget *textbutton;
41 GtkWidget *backbutton;43 GtkWidget *backbutton;
42 GtkWidget *autostart_xpad;44 GtkWidget *autostart_xpad;
43 GtkWidget *autostart_wait_systray;45 GtkWidget *autostart_wait_systray;
44 GtkWidget *autostart_delay; 46 GtkWidget *autostart_delay;
45 GtkWidget *autostart_new_pad;47 GtkWidget *autostart_new_pad;
46 GtkWidget *autostart_sticky;48 GtkWidget *autostart_sticky;
47 GtkWidget *autostart_display_pads;49 GtkWidget *autostart_display_pads;
@@ -50,7 +52,7 @@
50 GtkWidget *editcheck;52 GtkWidget *editcheck;
51 GtkWidget *confirmcheck;53 GtkWidget *confirmcheck;
5254
53 gulong fontcheck_handler; 55 gulong fontcheck_handler;
54 gulong font_handler;56 gulong font_handler;
55 gulong colorcheck_handler;57 gulong colorcheck_handler;
56 gulong text_handler;58 gulong text_handler;
@@ -60,7 +62,7 @@
60 gulong autostart_delay_handler;62 gulong autostart_delay_handler;
61 gulong autostart_new_pad_handler;63 gulong autostart_new_pad_handler;
62 gulong autostart_sticky_handler;64 gulong autostart_sticky_handler;
63 gulong autostart_display_pads_handler; 65 gulong autostart_display_pads_handler;
64 gulong tray_enabled_handler;66 gulong tray_enabled_handler;
65 gulong tray_click_handler;67 gulong tray_click_handler;
66 gulong editcheck_handler;68 gulong editcheck_handler;
@@ -83,51 +85,13 @@
8385
84G_DEFINE_TYPE_WITH_PRIVATE (XpadPreferences, xpad_preferences, GTK_TYPE_DIALOG)86G_DEFINE_TYPE_WITH_PRIVATE (XpadPreferences, xpad_preferences, GTK_TYPE_DIALOG)
8587
86static void xpad_preferences_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
87static void xpad_preferences_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
88static void xpad_preferences_constructed (GObject *object);
89static void xpad_preferences_finalize (GObject *object);
90static void xpad_preferences_response (GtkDialog *dialog, gint response);
91
92static void change_font_check (GtkToggleButton *button, XpadPreferences *pref);
93static void change_font_face (GtkFontButton *button, XpadPreferences *pref);
94static void change_color_check (GtkToggleButton *button, XpadPreferences *pref);
95static void change_text_color (GtkColorChooser *chooser, XpadPreferences *pref);
96static void change_back_color (GtkColorChooser *chooser, XpadPreferences *pref);
97static void change_autostart_xpad (GtkToggleButton *button, XpadPreferences *pref);
98static void change_autostart_wait_systray (GtkToggleButton *button, XpadPreferences *pref);
99static void change_autostart_delay (GtkComboBox *box, XpadPreferences *pref);
100static void change_autostart_new_pad (GtkToggleButton *button, XpadPreferences *pref);
101static void change_autostart_sticky (GtkToggleButton *button, XpadPreferences *pref);
102static void change_autostart_display_pads (GtkComboBox *box, XpadPreferences *pref);
103static void change_tray_enabled (GtkToggleButton *button, XpadPreferences *pref);
104static void change_tray_click (GtkComboBox *box, XpadPreferences *pref);
105static void change_edit_check (GtkToggleButton *button, XpadPreferences *pref);
106static void change_confirm_check (GtkToggleButton *button, XpadPreferences *pref);
107
108static void notify_fontname (XpadPreferences *pref);
109static void notify_text_color (XpadPreferences *pref);
110static void notify_back_color (XpadPreferences *pref);
111static void notify_autostart_xpad (XpadPreferences *pref);
112static void notify_autostart_wait_systray (XpadPreferences *pref);
113static void notify_autostart_delay (XpadPreferences *pref);
114static void notify_autostart_new_pad (XpadPreferences *pref);
115static void notify_autostart_sticky (XpadPreferences *pref);
116static void notify_autostart_display_pads (XpadPreferences *pref);
117static void notify_tray_enabled (XpadPreferences *pref);
118static void notify_tray_click (XpadPreferences *pref);
119static void notify_edit (XpadPreferences *pref);
120static void notify_confirm (XpadPreferences *pref);
121
122static GtkWidget * create_label (const gchar *label_text);
123
124static GtkWidget *_xpad_preferences = NULL;88static GtkWidget *_xpad_preferences = NULL;
12589
126enum90enum
127{91{
128 PROP_0,92 PROP_0,
129 PROP_SETTINGS,93 PROP_SETTINGS,
130 N_PROPERTIES94 N_PROPERTIES
131};95};
13296
133static GParamSpec *obj_prop[N_PROPERTIES] = { NULL, };97static GParamSpec *obj_prop[N_PROPERTIES] = { NULL, };
@@ -144,25 +108,447 @@
144 gtk_window_present (GTK_WINDOW (_xpad_preferences));108 gtk_window_present (GTK_WINDOW (_xpad_preferences));
145}109}
146110
147static void111static GtkWidget * create_label (const gchar *label_text)
148xpad_preferences_class_init (XpadPreferencesClass *klass)112{
149{113 GtkWidget *label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
150 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);114 "label", g_strconcat ("<b>", label_text, "</b>", NULL),
151115 "use-markup", TRUE,
152 gobject_class->constructed = xpad_preferences_constructed;116 "xalign", 0.0,
153 gobject_class->set_property = xpad_preferences_set_property;117 NULL));
154 gobject_class->get_property = xpad_preferences_get_property;118 return label;
155 gobject_class->finalize = xpad_preferences_finalize;119}
156120
157 obj_prop[PROP_SETTINGS] = g_param_spec_pointer ("settings", "Xpad settings", "Xpad global settings", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);121static void
158122xpad_preferences_set_property (GObject *object,
159 g_object_class_install_properties (gobject_class, N_PROPERTIES, obj_prop);123 guint prop_id,
160} 124 const GValue *value,
161125 GParamSpec *pspec)
162static void126{
163xpad_preferences_init (XpadPreferences *pref)127 XpadPreferences *pref = XPAD_PREFERENCES (object);
164{128
165 pref->priv = xpad_preferences_get_instance_private (pref);129 switch (prop_id)
130 {
131 case PROP_SETTINGS:
132 pref->priv->settings = g_value_get_pointer (value);
133 g_object_ref (pref->priv->settings);
134 break;
135
136 default:
137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
138 break;
139 }
140}
141
142static void
143xpad_preferences_get_property (GObject *object,
144 guint prop_id,
145 GValue *value,
146 GParamSpec *pspec)
147{
148 XpadPreferences *pref = XPAD_PREFERENCES (object);
149
150 switch (prop_id)
151 {
152 case PROP_SETTINGS:
153 g_value_set_pointer (value, pref->priv->settings);
154 break;
155
156 default:
157 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158 break;
159 }
160}
161
162static void
163xpad_preferences_finalize (GObject *object)
164{
165 XpadPreferences *pref = XPAD_PREFERENCES (object);
166
167 if (pref->priv->settings)
168 g_signal_handlers_disconnect_matched (pref->priv->settings, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, pref);
169
170 G_OBJECT_CLASS (xpad_preferences_parent_class)->finalize (object);
171}
172
173static void
174xpad_preferences_response (GtkDialog *dialog,
175 gint response)
176{
177 if (response == GTK_RESPONSE_CLOSE)
178 gtk_widget_destroy (GTK_WIDGET (dialog));
179}
180
181static void
182change_font_check (GtkToggleButton *button,
183 XpadPreferences *pref)
184{
185 g_signal_handler_block (pref->priv->settings, pref->priv->notify_font_handler);
186 if (!gtk_toggle_button_get_active (button))
187 g_object_set (pref->priv->settings, "fontname", NULL, NULL);
188 else
189 g_object_set (pref->priv->settings, "fontname", gtk_font_button_get_font_name (GTK_FONT_BUTTON (pref->priv->fontbutton)), NULL);
190 gtk_widget_set_sensitive (pref->priv->fontbutton, gtk_toggle_button_get_active (button));
191 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_font_handler);
192}
193
194static void
195change_font_face (GtkFontButton *button,
196 XpadPreferences *pref)
197{
198 g_signal_handler_block (pref->priv->settings, pref->priv->notify_font_handler);
199 g_object_set (pref->priv->settings, "fontname", gtk_font_button_get_font_name (button), NULL);
200 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_font_handler);
201}
202
203static void
204change_color_check (GtkToggleButton *button,
205 XpadPreferences *pref)
206{
207 g_signal_handler_block (pref->priv->settings, pref->priv->notify_text_handler);
208 g_signal_handler_block (pref->priv->settings, pref->priv->notify_back_handler);
209
210 if (!gtk_toggle_button_get_active (button))
211 g_object_set (pref->priv->settings, "text-color", NULL, "back-color", NULL, NULL);
212 else
213 {
214 GdkRGBA text_color, back_color;
215 gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (pref->priv->textbutton), &text_color);
216 gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (pref->priv->backbutton), &back_color);
217 g_object_set (pref->priv->settings, "text-color", &text_color, "back-color", &back_color, NULL);
218 }
219
220 gtk_widget_set_sensitive (pref->priv->colorbox, gtk_toggle_button_get_active (button));
221
222 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_text_handler);
223 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_back_handler);
224}
225
226static void
227change_text_color (GtkColorChooser *chooser,
228 XpadPreferences *pref)
229{
230 GdkRGBA text_color = {0, 0, 0, 0};
231 gtk_color_chooser_get_rgba (chooser, &text_color);
232
233 g_signal_handler_block (pref->priv->settings, pref->priv->notify_text_handler);
234 g_object_set (pref->priv->settings, "text-color", &text_color, NULL);
235 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_text_handler);
236}
237
238static void
239change_back_color (GtkColorChooser *chooser,
240 XpadPreferences *pref)
241{
242 GdkRGBA back_color = {0, 0, 0, 0};
243 gtk_color_chooser_get_rgba (chooser, &back_color);
244
245 g_signal_handler_block (pref->priv->settings, pref->priv->notify_back_handler);
246 g_object_set (pref->priv->settings, "back-color", &back_color, NULL);
247 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_back_handler);
248}
249
250static void
251change_autostart_xpad (GtkToggleButton *button,
252 XpadPreferences *pref)
253{
254 g_object_set (pref->priv->settings, "autostart-xpad", gtk_toggle_button_get_active (button), NULL);
255}
256
257static void
258change_autostart_wait_systray (GtkToggleButton *button,
259 XpadPreferences *pref)
260{
261 GKeyFile *keyfile;
262 GKeyFileFlags flags;
263 GError *error = NULL;
264 char *filename;
265 gboolean wait_systray;
266
267 wait_systray = gtk_toggle_button_get_active (button);
268
269 /* Create a new GKeyFile object and a bitwise list of flags. */
270 keyfile = g_key_file_new ();
271 filename = g_strdup_printf ("%s/.config/autostart/xpad.desktop", g_get_home_dir());
272 flags = G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS;
273
274 /* Load the GKeyFile from xpad.desktop or show an error message. */
275 if (!g_key_file_load_from_file (keyfile, filename, flags, &error)) {
276 gchar *errtext;
277 errtext = g_strdup_printf (_("Could not load %s\n%s"), filename, error->message);
278 xpad_app_error (NULL, _("Error changing wait for systray setting"), errtext);
279 g_free (errtext);
280
281 gtk_toggle_button_set_active (button, !wait_systray);
282 return;
283 }
284
285 g_key_file_set_boolean (keyfile, "Desktop Entry", "X-LXQt-Need-Tray", wait_systray);
286
287 if (!g_key_file_save_to_file (keyfile, filename, &error)) {
288 gchar *errtext;
289 errtext = g_strdup_printf (_("Could not save %s\n%s"), filename, error->message);
290 xpad_app_error (NULL, _("Error changing wait for systray setting"), errtext);
291 g_free (errtext);
292
293 gtk_toggle_button_set_active (button, !wait_systray);
294 return;
295 }
296
297 g_signal_handler_block (pref->priv->settings, pref->priv->notify_autostart_wait_systray_handler);
298 g_object_set (pref->priv->settings, "autostart-wait-systray", wait_systray, NULL);
299 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_autostart_wait_systray_handler);
300}
301
302static void
303change_autostart_new_pad (GtkToggleButton *button,
304 XpadPreferences *pref)
305{
306 g_signal_handler_block (pref->priv->settings, pref->priv->notify_autostart_new_pad_handler);
307 g_object_set (pref->priv->settings, "autostart-new-pad", gtk_toggle_button_get_active (button), NULL);
308 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_autostart_new_pad_handler);
309}
310
311static void
312change_autostart_sticky (GtkToggleButton *button,
313 XpadPreferences *pref)
314{
315 g_signal_handler_block (pref->priv->settings, pref->priv->notify_autostart_sticky_handler);
316 g_object_set (pref->priv->settings, "autostart-sticky", gtk_toggle_button_get_active (button), NULL);
317 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_autostart_sticky_handler);
318}
319
320static void
321change_autostart_delay (GtkComboBox *box,
322 XpadPreferences *pref)
323{
324 g_signal_handler_block(pref->priv->settings, pref->priv->notify_autostart_delay_handler);
325 g_object_set (pref->priv->settings, "autostart-delay", (guint) gtk_combo_box_get_active (box), NULL);
326 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_autostart_delay_handler);
327}
328
329static void
330change_autostart_display_pads (GtkComboBox *box,
331 XpadPreferences *pref)
332{
333 g_signal_handler_block (pref->priv->settings, pref->priv->notify_autostart_display_pads_handler);
334 g_object_set (pref->priv->settings, "autostart-display-pads", (guint) gtk_combo_box_get_active (box), NULL);
335 g_signal_handler_unblock(pref->priv->settings, pref->priv->notify_autostart_display_pads_handler);
336}
337
338static void
339change_tray_enabled (GtkToggleButton *button,
340 XpadPreferences *pref)
341{
342 g_object_set (pref->priv->settings, "tray-enabled", gtk_toggle_button_get_active (button), NULL);
343}
344
345static void
346change_tray_click (GtkComboBox *box,
347 XpadPreferences *pref)
348{
349 g_signal_handler_block(pref->priv->settings, pref->priv->notify_tray_click_handler);
350 g_object_set (pref->priv->settings, "tray-click-configuration", (guint) gtk_combo_box_get_active (box), NULL);
351 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_tray_click_handler);
352}
353
354static void
355change_edit_check (GtkToggleButton *button, XpadPreferences *pref)
356{
357 g_signal_handler_block (pref->priv->settings, pref->priv->notify_edit_handler);
358 g_object_set (pref->priv->settings, "edit-lock", gtk_toggle_button_get_active (button), NULL);
359 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_edit_handler);
360}
361
362static void
363change_confirm_check (GtkToggleButton *button,
364 XpadPreferences *pref)
365{
366 g_signal_handler_block (pref->priv->settings, pref->priv->notify_confirm_handler);
367 g_object_set (pref->priv->settings, "confirm-destroy", gtk_toggle_button_get_active (button), NULL);
368 g_signal_handler_unblock (pref->priv->settings, pref->priv->notify_confirm_handler);
369}
370
371static void
372notify_fontname (XpadPreferences *pref)
373{
374 const gchar *fontname;
375 g_object_get (pref->priv->settings, "fontname", &fontname, NULL);
376
377 g_signal_handler_block (pref->priv->fontbutton, pref->priv->font_handler);
378 g_signal_handler_block (pref->priv->fontcheck, pref->priv->fontcheck_handler);
379
380 if (fontname)
381 {
382 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->fontcheck), TRUE);
383 gtk_widget_set_sensitive (pref->priv->fontbutton, TRUE);
384 gtk_font_button_set_font_name (GTK_FONT_BUTTON (pref->priv->fontbutton), fontname);
385 }
386 else
387 {
388 gtk_widget_set_sensitive (pref->priv->fontbutton, FALSE);
389 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->antifontcheck), TRUE);
390 }
391
392 g_signal_handler_unblock (pref->priv->fontcheck, pref->priv->fontcheck_handler);
393 g_signal_handler_unblock (pref->priv->fontbutton, pref->priv->font_handler);
394}
395
396static void
397notify_text_color (XpadPreferences *pref)
398{
399 const GdkRGBA *text_color;
400 g_object_get (pref->priv->settings, "text-color", &text_color, NULL);
401
402 g_signal_handler_block (pref->priv->textbutton, pref->priv->text_handler);
403 g_signal_handler_block (pref->priv->colorcheck, pref->priv->colorcheck_handler);
404
405 if (text_color)
406 {
407 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->colorcheck), TRUE);
408 gtk_widget_set_sensitive (pref->priv->colorbox, TRUE);
409 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (pref->priv->textbutton), text_color);
410
411 }
412 else
413 {
414 gtk_widget_set_sensitive (pref->priv->colorbox, FALSE);
415 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->anticolorcheck), TRUE);
416 }
417
418 g_signal_handler_unblock (pref->priv->colorcheck, pref->priv->colorcheck_handler);
419 g_signal_handler_unblock (pref->priv->textbutton, pref->priv->text_handler);
420}
421
422static void
423notify_back_color (XpadPreferences *pref)
424{
425 const GdkRGBA *back_color;
426 g_object_get (pref->priv->settings, "back-color", &back_color, NULL);
427
428 g_signal_handler_block (pref->priv->backbutton, pref->priv->back_handler);
429 g_signal_handler_block (pref->priv->colorcheck, pref->priv->colorcheck_handler);
430
431 if (back_color)
432 {
433 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->colorcheck), TRUE);
434 gtk_widget_set_sensitive (pref->priv->colorbox, TRUE);
435 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (pref->priv->backbutton), back_color);
436 }
437 else
438 {
439 gtk_widget_set_sensitive (pref->priv->colorbox, FALSE);
440 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->anticolorcheck), TRUE);
441 }
442
443 g_signal_handler_unblock (pref->priv->colorcheck, pref->priv->colorcheck_handler);
444 g_signal_handler_unblock (pref->priv->backbutton, pref->priv->back_handler);
445}
446
447static void
448notify_autostart_xpad (XpadPreferences *pref)
449{
450 gboolean value;
451 g_object_get (pref->priv->settings, "autostart-xpad", &value, NULL);
452 g_signal_handler_block (pref->priv->autostart_xpad, pref->priv->autostart_xpad_handler);
453 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->autostart_xpad), value);
454 gtk_widget_set_sensitive (pref->priv->autostart_wait_systray, value);
455 if (value)
456 change_autostart_wait_systray (GTK_TOGGLE_BUTTON (pref->priv->autostart_wait_systray), pref);
457 g_signal_handler_unblock (pref->priv->autostart_xpad, pref->priv->autostart_xpad_handler);
458}
459
460static void
461notify_autostart_wait_systray (XpadPreferences *pref)
462{
463 gboolean value;
464 g_object_get (pref->priv->settings, "autostart-wait-systray", &value, NULL);
465 g_signal_handler_block (pref->priv->autostart_wait_systray, pref->priv->autostart_wait_systray_handler);
466 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->autostart_wait_systray), value);
467 g_signal_handler_unblock (pref->priv->autostart_wait_systray, pref->priv->autostart_wait_systray_handler);
468}
469
470static void
471notify_autostart_new_pad (XpadPreferences *pref)
472{
473 gboolean value;
474 g_object_get (pref->priv->settings, "autostart-new-pad", &value, NULL);
475 g_signal_handler_block (pref->priv->autostart_new_pad, pref->priv->autostart_new_pad_handler);
476 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->autostart_new_pad), value);
477 g_signal_handler_unblock (pref->priv->autostart_new_pad, pref->priv->autostart_new_pad_handler);
478}
479
480static void
481notify_autostart_sticky (XpadPreferences *pref)
482{
483 gboolean value;
484 g_object_get (pref->priv->settings, "autostart-sticky", &value, NULL);
485 g_signal_handler_block (pref->priv->autostart_sticky, pref->priv->autostart_sticky_handler);
486 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->autostart_sticky), value);
487 g_signal_handler_unblock (pref->priv->autostart_sticky, pref->priv->autostart_sticky_handler);
488}
489
490static void
491notify_autostart_delay (XpadPreferences *pref)
492{
493 guint value;
494 g_object_get (pref->priv->settings, "autostart-delay", &value, NULL);
495 g_signal_handler_block (pref->priv->autostart_delay, pref->priv->autostart_delay_handler);
496 gtk_combo_box_set_active (GTK_COMBO_BOX (pref->priv->autostart_delay), value);
497 g_signal_handler_unblock (pref->priv->autostart_delay, pref->priv->autostart_delay_handler);
498}
499
500static void
501notify_autostart_display_pads (XpadPreferences *pref)
502{
503 guint value;
504 g_object_get (pref->priv->settings, "autostart-display-pads", &value, NULL);
505 g_signal_handler_block (pref->priv->autostart_display_pads, pref->priv->autostart_display_pads_handler);
506 gtk_combo_box_set_active (GTK_COMBO_BOX (pref->priv->autostart_display_pads), value);
507 g_signal_handler_unblock (pref->priv->autostart_display_pads, pref->priv->autostart_display_pads_handler);
508}
509
510static void
511notify_tray_enabled (XpadPreferences *pref)
512{
513 gboolean value;
514 g_object_get (pref->priv->settings, "tray-enabled", &value, NULL);
515 g_signal_handler_block (pref->priv->tray_enabled, pref->priv->tray_enabled_handler);
516 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->tray_enabled), value);
517 gtk_widget_set_sensitive (pref->priv->tray_click_configuration, value);
518 gtk_widget_set_sensitive (pref->priv->autostart_display_pads, value);
519 if (!value)
520 g_object_set (pref->priv->settings, "autostart-display-pads", 0, NULL);
521 g_signal_handler_unblock (pref->priv->tray_enabled, pref->priv->tray_enabled_handler);
522}
523
524static void
525notify_tray_click (XpadPreferences *pref)
526{
527 guint value;
528 g_object_get (pref->priv->settings, "tray-click-configuration", &value, NULL);
529 g_signal_handler_block (pref->priv->tray_click_configuration, pref->priv->tray_click_handler);
530 gtk_combo_box_set_active (GTK_COMBO_BOX (pref->priv->tray_click_configuration), value);
531 g_signal_handler_unblock (pref->priv->tray_click_configuration, pref->priv->tray_click_handler);
532}
533
534static void
535notify_edit (XpadPreferences *pref)
536{
537 gboolean value;
538 g_object_get (pref->priv->settings, "edit-lock", &value, NULL);
539 g_signal_handler_block (pref->priv->editcheck, pref->priv->editcheck_handler);
540 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->editcheck), value);
541 g_signal_handler_unblock (pref->priv->editcheck, pref->priv->editcheck_handler);
542}
543
544static void
545notify_confirm (XpadPreferences *pref)
546{
547 gboolean value;
548 g_object_get (pref->priv->settings, "confirm-destroy", &value, NULL);
549 g_signal_handler_block (pref->priv->confirmcheck, pref->priv->confirmcheck_handler);
550 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->confirmcheck), value);
551 g_signal_handler_unblock (pref->priv->confirmcheck, pref->priv->confirmcheck_handler);
166}552}
167553
168static void xpad_preferences_constructed (GObject *object)554static void xpad_preferences_constructed (GObject *object)
@@ -263,10 +649,10 @@
263 else649 else
264 {650 {
265 PangoFontDescription *font;651 PangoFontDescription *font;
266 652
267 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->antifontcheck), TRUE);653 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->antifontcheck), TRUE);
268 gtk_widget_set_sensitive (pref->priv->fontbutton, FALSE);654 gtk_widget_set_sensitive (pref->priv->fontbutton, FALSE);
269 655
270 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font, NULL);656 gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, GTK_STYLE_PROPERTY_FONT, &font, NULL);
271 gtk_font_button_set_font_name (GTK_FONT_BUTTON (pref->priv->fontbutton), pango_font_description_to_string(font));657 gtk_font_button_set_font_name (GTK_FONT_BUTTON (pref->priv->fontbutton), pango_font_description_to_string(font));
272 pango_font_description_free (font);658 pango_font_description_free (font);
@@ -288,17 +674,17 @@
288 gtk_widget_set_sensitive (pref->priv->colorbox, FALSE);674 gtk_widget_set_sensitive (pref->priv->colorbox, FALSE);
289 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (pref->priv->backbutton), &theme_background_color);675 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (pref->priv->backbutton), &theme_background_color);
290 }676 }
291 677
292 alignment = gtk_alignment_new (1, 1, 1, 1);678 alignment = gtk_alignment_new (1, 1, 1, 1);
293 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);679 gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 0, 12, 0);
294 gtk_container_add (GTK_CONTAINER (alignment), pref->priv->colorbox);680 gtk_container_add (GTK_CONTAINER (alignment), pref->priv->colorbox);
295 681
296 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));682 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));
297683
298 gtk_box_pack_start (vbox, pref->priv->antifontcheck, FALSE, FALSE, 0);684 gtk_box_pack_start (vbox, pref->priv->antifontcheck, FALSE, FALSE, 0);
299 gtk_box_pack_start (vbox, GTK_WIDGET (font_hbox), FALSE, FALSE, 0);685 gtk_box_pack_start (vbox, GTK_WIDGET (font_hbox), FALSE, FALSE, 0);
300 gtk_box_pack_start (appearance_vbox, GTK_WIDGET (vbox), FALSE, FALSE, 0);686 gtk_box_pack_start (appearance_vbox, GTK_WIDGET (vbox), FALSE, FALSE, 0);
301 687
302 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));688 vbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_VERTICAL, 6));
303689
304 gtk_box_pack_start (vbox, pref->priv->anticolorcheck, FALSE, FALSE, 0);690 gtk_box_pack_start (vbox, pref->priv->anticolorcheck, FALSE, FALSE, 0);
@@ -358,7 +744,7 @@
358 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->autostart_sticky), autostart_sticky);744 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (pref->priv->autostart_sticky), autostart_sticky);
359745
360 label = gtk_label_new (_("Delay in seconds"));746 label = gtk_label_new (_("Delay in seconds"));
361 pref->priv->autostart_delay = gtk_combo_box_text_new(); 747 pref->priv->autostart_delay = gtk_combo_box_text_new();
362 guint i;748 guint i;
363 for (i=0; i<15; i++)749 for (i=0; i<15; i++)
364 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (pref->priv->autostart_delay), g_strdup_printf ("%i", i));750 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (pref->priv->autostart_delay), g_strdup_printf ("%i", i));
@@ -482,7 +868,7 @@
482 pref->priv->notify_confirm_handler = g_signal_connect_swapped (pref->priv->settings, "notify::confirm-destroy", G_CALLBACK (notify_confirm), pref);868 pref->priv->notify_confirm_handler = g_signal_connect_swapped (pref->priv->settings, "notify::confirm-destroy", G_CALLBACK (notify_confirm), pref);
483 pref->priv->notify_tray_enabled_handler = g_signal_connect_swapped (pref->priv->settings, "notify::tray-enabled", G_CALLBACK (notify_tray_enabled), pref);869 pref->priv->notify_tray_enabled_handler = g_signal_connect_swapped (pref->priv->settings, "notify::tray-enabled", G_CALLBACK (notify_tray_enabled), pref);
484 pref->priv->notify_tray_click_handler = g_signal_connect_swapped (pref->priv->settings, "notify::tray-click-configuration", G_CALLBACK(notify_tray_click), pref);870 pref->priv->notify_tray_click_handler = g_signal_connect_swapped (pref->priv->settings, "notify::tray-click-configuration", G_CALLBACK(notify_tray_click), pref);
485 871
486 g_object_unref (size_group_labels);872 g_object_unref (size_group_labels);
487873
488 /* Initiliaze the GUI logic */874 /* Initiliaze the GUI logic */
@@ -498,423 +884,23 @@
498 g_object_set (G_OBJECT (pref), "default-width", (gint) (req.height * 0.8), NULL);884 g_object_set (G_OBJECT (pref), "default-width", (gint) (req.height * 0.8), NULL);
499}885}
500886
501static GtkWidget * create_label (const gchar *label_text) {
502 GtkWidget *label = GTK_WIDGET (g_object_new (GTK_TYPE_LABEL,
503 "label", g_strconcat ("<b>", label_text, "</b>", NULL),
504 "use-markup", TRUE,
505 "xalign", 0.0,
506 NULL));
507 return label;
508}
509
510static void
511xpad_preferences_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
512{
513 XpadPreferences *pref = XPAD_PREFERENCES (object);
514
515 switch (prop_id)
516 {
517 case PROP_SETTINGS:
518 pref->priv->settings = g_value_get_pointer (value);
519 g_object_ref (pref->priv->settings);
520 break;
521
522 default:
523 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
524 break;
525 }
526}
527
528static void
529xpad_preferences_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
530{
531 XpadPreferences *pref = XPAD_PREFERENCES (object);
532
533 switch (prop_id)
534 {
535 case PROP_SETTINGS:
536 g_value_set_pointer (value, pref->priv->settings);
537 break;
538
539 default:
540 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
541 break;
542 }
543}
544
545static void
546xpad_preferences_finalize (GObject *object)
547{
548 XpadPreferences *pref = XPAD_PREFERENCES (object);
549
550 if (pref->priv->settings)
551 g_signal_handlers_disconnect_matched (pref->priv->settings, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, pref);
552
553 G_OBJECT_CLASS (xpad_preferences_parent_class)->finalize (object);
554}
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches