1
/* $Id: clipman.c 6467 2009-01-15 17:51:07Z mmassonnet $
3
* Copyright (c) 2006-2007 Nick Schermer <nick@xfce.org>
4
* 2008-2009 Mike Massonnet <mmassonnet@xfce.org>
5
* 2008-2009 David Collins <david.8.collins@gmail.com>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 2 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU Library General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31
#include <libxfcegui4/libxfcegui4.h>
32
#include <libxfce4util/libxfce4util.h>
33
#include <libxfce4panel/xfce-panel-plugin.h>
34
#include <libxfce4panel/xfce-panel-convenience.h>
37
#include "clipman-dialogs.h"
40
static GtkClipboard *primaryClip;
41
static GtkClipboard *defaultClip;
43
/* For event-driven clipboard_change() function */
44
gboolean MouseSelecting=FALSE;
45
gboolean ShiftSelecting=FALSE;
47
/* Register the plugin */
49
clipman_construct (XfcePanelPlugin *plugin);
51
XFCE_PANEL_PLUGIN_REGISTER_EXTERNAL (clipman_construct);
54
clipman_free_clip (ClipmanClip *clip)
56
if (clip->datatype == RAWTEXT) {
58
} else if (clip->datatype == IMAGE) {
59
g_object_unref(clip->data);
63
panel_slice_free (ClipmanClip, clip);
65
DBG ("Clip successfully freed");
69
clipman_set_data (ClipmanClip *clip, GtkClipboard *clipboard)
71
DBG ("Clipman_set_data ..");
72
if (clip->datatype == RAWTEXT) {
73
gtk_clipboard_set_text (clipboard, clip->data, -1);
74
} else if (clip->datatype == IMAGE) {
75
gtk_clipboard_set_image (clipboard, (GdkPixbuf *)clip->data);
77
DBG ("Clip data copied to clipboard");
81
clipman_destroy_menu (GtkWidget *menu,
82
ClipmanPlugin *clipman)
86
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (clipman->button), FALSE);
88
gtk_widget_destroy (menu);
90
/* Clear ClipmanAction structs */
91
for (l = clipman->actions; l != NULL; l = l->next)
92
panel_slice_free (ClipmanAction, l->data);
93
g_slist_free (clipman->actions);
94
clipman->actions = NULL;
96
DBG ("Menu Destroyed");
99
/* Clear list of items AND both clipboards */
101
clipman_clear (GtkWidget *mi, GdkEventButton *ev, ClipmanPlugin *clipman) {
105
if (xfce_confirm (_("Are you sure you want to clear the history?"),
108
gtk_clipboard_clear (primaryClip);
109
gtk_clipboard_clear (defaultClip);
110
clipman->DefaultIndex=-1;
111
clipman->PrimaryIndex=-1;
113
while (clipman->clips->len > 0)
115
clip = g_ptr_array_index (clipman->clips, 0);
116
g_ptr_array_remove (clipman->clips, clip);
117
clipman_free_clip (clip);
123
/* Remove the oldest items - these are at the start of the list */
125
clipman_array_remove_oldest (ClipmanPlugin *clipman)
130
while (clipman->clips->len > clipman->HistoryItems) {
132
// Leave items in list if they are active
133
for (i=0; i<2; ++i) {
134
if (clipman->DefaultIndex != i && clipman->PrimaryIndex != i) break;
137
clip = g_ptr_array_index (clipman->clips, i);
138
g_ptr_array_remove (clipman->clips, clip);
139
clipman_free_clip (clip);
140
/* Adjust indexes to clipboard data */
141
if (clipman->DefaultIndex > i) --clipman->DefaultIndex;
142
if (clipman->PrimaryIndex > i) --clipman->PrimaryIndex;
144
DBG("A clip have been removed");
149
clipman_array_remove_image_data (ClipmanPlugin *clipman)
154
DBG ("Removing image data from array");
156
for (i=0; i<clipman->clips->len; ++i) {
158
clip = g_ptr_array_index (clipman->clips, i);
159
if (clip->datatype == IMAGE) {
160
g_ptr_array_remove (clipman->clips, clip);
161
clipman_free_clip (clip);
162
/* Adjust indexes to clipboard data */
163
if (clipman->DefaultIndex == i) clipman->DefaultIndex=-1;
164
if (clipman->DefaultIndex > i) --clipman->DefaultIndex;
170
clipman_create_title (gchar *text,
173
gchar *short_text, *tmp = NULL;
176
g_return_val_if_fail (G_LIKELY (NULL != text), NULL);
178
if (G_UNLIKELY (!g_utf8_validate (text, -1, NULL)))
181
short_text = g_strstrip (g_strdup (text));
184
if (g_utf8_strlen (short_text, -1) > length)
186
offset = g_utf8_offset_to_pointer (short_text, length);
187
tmp = g_strndup (short_text, offset - short_text);
190
short_text = g_strconcat (tmp, "...", NULL); /* Ellipsis */
195
tmp = g_strdelimit (short_text, "\n\r\t", ' ');
196
short_text = g_markup_escape_text (tmp, -1);
202
/* Add new item to the end of the list */
204
clipman_add_clip (ClipmanPlugin *clipman, void *data, ClipboardType cliptype, ClipDataType datatype) {
208
if (G_LIKELY (data != NULL)) {
209
// && G_LIKELY (strcmp (data, ""))) {
211
clip = panel_slice_new0 (ClipmanClip);
213
if (datatype == RAWTEXT) {
214
clip->title = clipman_create_title (data, clipman->MenuCharacters);
216
/* Change this to store a pixbuf preview */
217
clip->title = clipman_create_title (CLIPIMAGETITLE, clipman->MenuCharacters);
218
clip->preview = exo_gdk_pixbuf_scale_ratio (GDK_PIXBUF (data), 128);
221
/* No valid title could be created, drop it */
222
if (clip->title == NULL) {
223
DBG("A title couldn't be created");
224
panel_slice_free (ClipmanClip, clip);
228
/* Make a copy of the data and add to the pointer array */
229
if (datatype == RAWTEXT) {
230
clip->data = g_strdup(data);
231
clip->datatype = RAWTEXT;
232
} else if (datatype == IMAGE) {
233
clip->data = gdk_pixbuf_copy((GdkPixbuf *)data);
234
DBG("Made copy of image");
235
clip->datatype = IMAGE;
236
// Remove any other image data first ..
237
clipman_array_remove_image_data(clipman);
239
g_ptr_array_add (clipman->clips, clip);
241
/* Indicate this item is in the clipboard */
242
if (cliptype == DEFAULT) {
243
clipman->DefaultIndex=clipman->clips->len-1;
244
} else if (cliptype == PRIMARY) {
245
clipman->PrimaryIndex=clipman->clips->len-1;
247
DBG("Added clip %d of %d", clipman->clips->len, clipman->HistoryItems);
251
/* See if the text/image is already in the list. If so, mark it as the current DEFAULT or PRIMARY clipboard.
252
If not found then return FALSE.
253
Currently, this will always return FALSE for IMAGE data. */
255
clipman_exists (ClipmanPlugin *clipman, void *data, ClipboardType cliptype, ClipDataType datatype) {
260
/* Walk through the array backwards, because
261
* if the text exists, this will probably be the newest */
262
for (i=(gint)clipman->clips->len-1; i>=0; i--) {
264
clip = g_ptr_array_index (clipman->clips, i);
266
if (G_LIKELY(clip->data != NULL)) {
267
if (datatype == RAWTEXT && strcmp(clip->data, data) == 0) {
268
if (cliptype == PRIMARY) {
269
clipman->PrimaryIndex=i;
270
DBG("String re-selected");
271
} else if (cliptype == DEFAULT) {
272
clipman->DefaultIndex=i;
273
DBG("Selection Copied");
283
clipman_item_clicked (GtkWidget *mi,
285
ClipmanAction *action)
287
gboolean defaultcleared, primarycleared;
289
/* Left mouse button - put item in BOTH clipboards */
290
if (ev->button == 1) {
291
gtk_clipboard_clear (defaultClip);
292
clipman_set_data (action->clip, defaultClip);
293
//gtk_clipboard_set_text (defaultClip, action->clip->data, -1);
294
action->clipman->DefaultIndex = action->index;
295
DBG ("Clip copied to default clipboard");
297
if (action->clipman->AddSelect) {
298
gtk_clipboard_clear (primaryClip);
299
clipman_set_data (action->clip, primaryClip);
300
action->clipman->PrimaryIndex = action->index;
301
DBG ("Clip copied to primary clipboard");
304
/* Right mouse button - remove item */
305
} else if (ev->button == 3) {
307
defaultcleared=FALSE;
308
primarycleared=FALSE;
310
DBG ("Removed the selected clip from the History");
311
/* If this item is in clipboard, clear the clipbard */
312
if (action->clipman->DefaultIndex == action->index) {
313
gtk_clipboard_clear (defaultClip);
315
} else if (action->clipman->DefaultIndex > action->index) {
316
// index needs adjustment
317
--action->clipman->DefaultIndex;
320
if (action->clipman->AddSelect) {
321
/* If this item is in clipboard, clear the clipbard */
322
if (action->clipman->PrimaryIndex == action->index) {
323
gtk_clipboard_clear (primaryClip);
325
} else if (action->clipman->PrimaryIndex > action->index) {
326
// index needs adjustment
327
--action->clipman->PrimaryIndex;
331
/* Remove chosen item from the list */
332
g_ptr_array_remove (action->clipman->clips, action->clip);
333
clipman_free_clip (action->clip);
334
guint len = action->clipman->clips->len;
336
/* List is now empty */
338
if (defaultcleared) {
339
gtk_clipboard_set_text (defaultClip, "", -1); // this might not be needed?
340
action->clipman->DefaultIndex = -1;
342
if (primarycleared) {
343
gtk_clipboard_set_text (primaryClip, "", -1); // this might not be needed?
344
action->clipman->PrimaryIndex = -1;
348
/* Get the newest item left in the list */
349
ClipmanClip *clip = g_ptr_array_index (action->clipman->clips, len-1);
351
/* If Clipboard has been cleared, put in a replacement */
352
if (defaultcleared) {
353
clipman_set_data (clip, defaultClip);
354
action->clipman->DefaultIndex = len-1;
356
if (primarycleared) {
357
clipman_set_data (clip, primaryClip);
358
action->clipman->PrimaryIndex = len-1;
367
clipman_create_menuitem (ClipmanAction *action,
370
ClipMenuFormat format) {
373
gchar *title, *string_num;
375
if (action->clipman->ItemNumbers) {
377
string_num = g_strdup_printf("<tt><span size=\"smaller\">%d. </span></tt> ", number);
379
string_num = g_strdup_printf("<tt><span size=\"smaller\">%d.</span></tt> ", number);
381
string_num = g_strdup ("");
385
title = g_strdup_printf("%s<b>%s</b>", string_num, action->clip->title);
386
else if (format==ITALICS)
387
title = g_strdup_printf("%s<i>%s</i>", string_num, action->clip->title);
389
title = g_strdup_printf("%s%s", string_num, action->clip->title);
393
mi = gtk_menu_item_new_with_label ("");
394
gtk_label_set_markup (GTK_LABEL (GTK_BIN (mi)->child), title);
401
clipman_create_imagemenuitem (ClipmanAction *action) {
403
GtkWidget *mi, *image;
405
mi = gtk_menu_item_new ();
406
image = gtk_image_new_from_pixbuf (action->clip->preview);
407
gtk_container_add (GTK_CONTAINER (mi), image);
413
clipman_build_menu_body (GtkWidget *menu, ClipmanPlugin *clipman) {
416
ClipmanAction *action = NULL;
420
for (i=clipman->clips->len; i--;) {
421
clip = g_ptr_array_index (clipman->clips, i);
423
action = panel_slice_new0 (ClipmanAction);
424
action->clipman = clipman;
428
if (clip->datatype == RAWTEXT) {
429
if (clipman->DefaultIndex == i) {
430
mi = clipman_create_menuitem (action, clipman->MenuCharacters,
431
clipman->clips->len-i, BOLD);
433
else if (clipman->PrimaryIndex == i) {
434
mi = clipman_create_menuitem (action, clipman->MenuCharacters,
435
clipman->clips->len-i, ITALICS);
437
mi = clipman_create_menuitem (action, clipman->MenuCharacters,
438
clipman->clips->len-i, PLAIN);
440
} else if (clip->datatype == IMAGE) {
441
mi = clipman_create_imagemenuitem (action);
444
clipman->actions = g_slist_prepend (clipman->actions, action);
445
g_signal_connect (G_OBJECT(mi), "button_release_event",
446
G_CALLBACK(clipman_item_clicked), action);
447
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
450
mi = gtk_separator_menu_item_new ();
451
gtk_widget_set_sensitive (mi, FALSE);
452
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
454
mi = gtk_menu_item_new_with_label (_("Clear History"));
455
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
457
g_signal_connect (G_OBJECT (mi), "button_release_event",
458
G_CALLBACK (clipman_clear), clipman);
462
clipman_position_menu (GtkMenu *menu,
466
ClipmanPlugin *clipman)
473
gtk_widget_size_request (GTK_WIDGET (menu), &req);
475
gdk_window_get_origin (GTK_WIDGET (clipman->plugin)->window, x, y);
477
switch (xfce_panel_plugin_get_screen_position(clipman->plugin))
479
case XFCE_SCREEN_POSITION_SW_H:
480
case XFCE_SCREEN_POSITION_S:
481
case XFCE_SCREEN_POSITION_SE_H:
486
case XFCE_SCREEN_POSITION_NW_H:
487
case XFCE_SCREEN_POSITION_N:
488
case XFCE_SCREEN_POSITION_NE_H:
490
*y += clipman->button->allocation.height;
493
case XFCE_SCREEN_POSITION_NW_V:
494
case XFCE_SCREEN_POSITION_W:
495
case XFCE_SCREEN_POSITION_SW_V:
497
*x += clipman->button->allocation.width;
498
*y += clipman->button->allocation.height - req.height;
501
case XFCE_SCREEN_POSITION_NE_V:
502
case XFCE_SCREEN_POSITION_E:
503
case XFCE_SCREEN_POSITION_SE_V:
506
*y += clipman->button->allocation.height - req.height;
509
case XFCE_SCREEN_POSITION_FLOATING_H:
510
case XFCE_SCREEN_POSITION_FLOATING_V:
511
case XFCE_SCREEN_POSITION_NONE:
513
gdk_display_get_pointer(gtk_widget_get_display(GTK_WIDGET(clipman->plugin)),
517
screen = gtk_widget_get_screen (clipman->button);
518
num = gdk_screen_get_monitor_at_window (screen, clipman->button->window);
519
gdk_screen_get_monitor_geometry (screen, num, &geom);
521
if (*x > geom.x + geom.width - req.width)
522
*x = geom.x + geom.width - req.width;
526
if (*y > geom.y + geom.height - req.height)
527
*y = geom.y + geom.height - req.height;
532
/* Show list when the clipman icon is clicked with the left mouse button */
534
clipman_icon_clicked (GtkWidget *button,
536
ClipmanPlugin *clipman)
542
if (ev->button != 1) return FALSE;
544
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (clipman->button), TRUE);
546
menu = gtk_menu_new ();
548
title = g_strdup_printf("<span weight=\"bold\">%s</span>", _("Clipman History"));
549
mi = gtk_menu_item_new_with_label ("");
550
gtk_label_set_markup(GTK_LABEL(GTK_BIN(mi)->child), title);
551
gtk_widget_set_sensitive (mi, FALSE);
552
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
554
mi = gtk_separator_menu_item_new ();
555
gtk_widget_set_sensitive (mi, FALSE);
556
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
558
if (G_LIKELY (clipman->clips->len > 0)) {
559
clipman_build_menu_body (menu, clipman);
561
mi = gtk_menu_item_new_with_label (_("< Clipboard Empty >"));
562
gtk_widget_set_sensitive (mi, FALSE);
563
gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
566
gtk_widget_show_all (menu);
568
/* Also destroy the menu items when nothing is clicked */
569
g_signal_connect (G_OBJECT(menu), "deactivate",
570
G_CALLBACK(clipman_destroy_menu), clipman);
572
gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
573
(GtkMenuPositionFunc) clipman_position_menu,
575
gtk_get_current_event_time ());
580
/* Called when a program closes. */
582
clipman_refill_clipboard (ClipmanPlugin *clipman,
587
if (clipman->clips->len > 0) {
589
if (type == DEFAULT) {
590
clip = g_ptr_array_index(clipman->clips, clipman->DefaultIndex);
591
clipman_set_data (clip, defaultClip);
592
} else if (type == PRIMARY) {
593
clip = g_ptr_array_index(clipman->clips, clipman->PrimaryIndex);
594
clipman_set_data (clip, primaryClip);
596
DBG("Active clip restored");
600
/* This function is called when populating the clipboard in these events -
601
- user selects data - add to list
602
- user copies data to clipboard - add to list
603
- program holding the DEFAULT clipboard closes down - populate DEFAULT clipboard with active list item
604
- program holding the PRIMARY clipboard closes down - populate PRIMARY clipboard with active list item
606
static void clipman_clipboard_changed(GtkClipboard *clipboard, ClipmanPlugin *clipman, GdkOwnerChange reason) {
608
gchar *ptext = NULL, *dtext;
610
// Information for the programmer
611
if (reason == GDK_OWNER_CHANGE_DESTROY) {
612
DBG("GDK_OWNER_CHANGE_DESTROY");
615
/* DEFAULT clipboard - 'Copied' data */
616
if (clipboard == defaultClip) {
618
// Program holding selection has closed
619
// (Mousepad gives GDK_OWNER_CHANGE_CLOSE, Kolorpaint gives GDK_OWNER_CHANGE_DESTROY)
620
if (reason == GDK_OWNER_CHANGE_CLOSE || reason == GDK_OWNER_CHANGE_DESTROY) {
621
clipman_refill_clipboard (clipman, DEFAULT);
625
// User copied data to clipboard
626
if (reason == GDK_OWNER_CHANGE_NEW_OWNER) {
628
dtext = gtk_clipboard_wait_for_text (defaultClip);
630
if (!clipman_exists (clipman, dtext, DEFAULT, RAWTEXT)) {
632
clipman_add_clip (clipman, dtext, DEFAULT, RAWTEXT);
633
clipman_array_remove_oldest (clipman);
637
GdkPixbuf *image = gtk_clipboard_wait_for_image(defaultClip);
639
if (!clipman_exists (clipman, image, DEFAULT, IMAGE)) {
640
DBG("Image copy ..");
641
clipman_add_clip (clipman, image, DEFAULT, IMAGE);
642
clipman_array_remove_oldest (clipman);
644
g_object_unref(image);
650
/* PRIMARY - only if 'Add Selections' is ticked */
651
if (clipboard == primaryClip && clipman->AddSelect) {
652
// Program holding selection has closed - restore Primary clipboard
653
if (reason == GDK_OWNER_CHANGE_CLOSE || reason == GDK_OWNER_CHANGE_DESTROY) {
654
clipman_refill_clipboard (clipman, PRIMARY);
658
if (reason == GDK_OWNER_CHANGE_NEW_OWNER) {
659
// Get selected - TEXT only
660
ptext = gtk_clipboard_wait_for_text (primaryClip);
661
// User has selected text.
663
if (!clipman_exists (clipman, ptext, PRIMARY, RAWTEXT)) {
664
DBG("Text select done");
665
clipman_add_clip (clipman, ptext, PRIMARY, RAWTEXT);
666
clipman_array_remove_oldest (clipman);
668
//gtk_clipboard_set_text (defaultClip, ptext, -1);
671
// If an image has been selected, don't process it - but reset PrimaryIndex
672
} else if (gtk_clipboard_wait_is_image_available(primaryClip)) {
673
clipman->PrimaryIndex=-1;
682
- user copies data to clipboard
683
- program holding a clipboard closes down
685
static void clipboard_changed(GtkClipboard *clipboard, GdkEvent *event, ClipmanPlugin *clipman) {
687
// Signal has been sent by this plugin
688
// (Found a GdkWindow that wraps the native X-window)
689
if (gdk_window_lookup(((GdkEventOwnerChange*)event)->owner)!=NULL) {
690
DBG("Signal Ignored");
694
/* Note this extra effort is only required for the PRIMARY selects
695
in some applications */
696
if (clipboard == primaryClip && clipman->AddSelect) {
697
GdkModifierType state;
698
gdk_window_get_pointer(NULL, NULL, NULL, &state);
699
if (state & GDK_BUTTON1_MASK) {
700
DBG("Left btn pressed");
702
return; // not done yet
703
} else if (state & GDK_SHIFT_MASK) {
704
DBG("Shift key pressed");
706
return; // not done yet
710
/* Reason the signal was sent */
711
GdkOwnerChange reason = ((GdkEventOwnerChange*)event)->reason;
712
clipman_clipboard_changed(clipboard, clipman, reason);
716
/* This runs every 0.5 seconds - minimize what it does. */
717
static gboolean clipman_timed_poll (ClipmanPlugin *clipman)
719
// Nearly always, this is all this function will do ..
720
if (!MouseSelecting && !ShiftSelecting) return TRUE;
722
GdkModifierType state;
723
gdk_window_get_pointer(NULL, NULL, NULL, &state);
724
if (MouseSelecting==TRUE && !(state & GDK_BUTTON1_MASK)) MouseSelecting=FALSE;
725
if (ShiftSelecting==TRUE && !(state & GDK_SHIFT_MASK)) ShiftSelecting=FALSE;
727
// Now that the selection is finished, run the necessary code ..
728
if (!MouseSelecting && !ShiftSelecting) {
729
DBG("Finished selecting");
730
clipman_clipboard_changed(primaryClip, clipman, GDK_OWNER_CHANGE_NEW_OWNER);
737
clipman_reset_timeout (ClipmanPlugin *clipman)
739
if (!(clipman->killTimeout))
741
if (clipman->TimeoutId != 0)
742
g_source_remove (clipman->TimeoutId);
744
clipman->TimeoutId = g_timeout_add_full (G_PRIORITY_LOW,
746
(GSourceFunc) clipman_timed_poll,
748
(GDestroyNotify) clipman_reset_timeout);
753
clipman_save (XfcePanelPlugin *plugin,
754
ClipmanPlugin *clipman)
756
gchar *file, *image_path;
764
/* Save the preferences */
765
DBG("Saving clipman preferences");
767
file = xfce_resource_save_location (XFCE_RESOURCE_CONFIG, "xfce4/panel/clipman.rc", TRUE);
769
if (G_UNLIKELY (!file))
772
rc = xfce_rc_simple_open (file, FALSE);
775
xfce_rc_set_group (rc, "Properties");
777
xfce_rc_write_bool_entry (rc, "ExitSave", clipman->ExitSave);
778
xfce_rc_write_bool_entry (rc, "AddSelect", clipman->AddSelect);
780
xfce_rc_write_bool_entry (rc, "ItemNumbers", clipman->ItemNumbers);
782
xfce_rc_write_int_entry (rc, "HistoryItems", clipman->HistoryItems);
783
xfce_rc_write_int_entry (rc, "MenuCharacters", clipman->MenuCharacters);
788
if (clipman->ExitSave &&
789
clipman->clips->len > 0
792
DBG("Saving the clipboard history");
794
file = xfce_resource_save_location (XFCE_RESOURCE_CACHE, "xfce4/clipman/textsrc", TRUE);
797
g_warning ("Unable to save the clipman history");
801
texts = g_malloc0 (clipman->clips->len * sizeof (gchar*));
802
for (n_texts = i = 0; i < clipman->clips->len; i++)
804
clip = g_ptr_array_index (clipman->clips, i);
807
if (clip->datatype == IMAGE)
809
image_path = xfce_resource_save_location (XFCE_RESOURCE_CACHE, "xfce4/clipman/image.png", FALSE);
810
gdk_pixbuf_save (GDK_PIXBUF (clip->data), image_path, "png", NULL, NULL);
815
texts[n_texts++] = clip->data;
820
keyfile = g_key_file_new ();
821
g_key_file_set_string_list (keyfile, "texts", "texts", texts, n_texts);
822
data = g_key_file_to_data (keyfile, NULL, NULL);
823
g_file_set_contents (file, data, -1, NULL);
825
g_key_file_free (keyfile);
833
clipman_read (ClipmanPlugin *clipman)
838
gchar **texts = NULL;
842
/* Because Clipman is unique, we use 1 config file */
844
file = xfce_panel_plugin_save_location (clipman->plugin, FALSE);
845
DBG("Read from file: %s", file);
848
/* Restore the preferences */
849
DBG ("Restoring preferences");
850
file = xfce_resource_save_location (XFCE_RESOURCE_CONFIG, "xfce4/panel/clipman.rc", TRUE);
852
if (G_UNLIKELY (!file))
855
rc = xfce_rc_simple_open (file, FALSE);
858
xfce_rc_set_group (rc, "Properties");
860
clipman->ExitSave = xfce_rc_read_bool_entry (rc, "ExitSave", DEFEXITSAVE);
861
clipman->AddSelect = xfce_rc_read_bool_entry (rc, "AddSelect", DEFADDSELECT);
862
clipman->ItemNumbers = xfce_rc_read_bool_entry (rc, "ItemNumbers", DEFITEMNUMBERS);
864
clipman->HistoryItems = xfce_rc_read_int_entry (rc, "HistoryItems", DEFHISTORY);
865
clipman->MenuCharacters = xfce_rc_read_int_entry (rc, "MenuCharacters", DEFCHARS);
867
if (clipman->HistoryItems > MAXHISTORY)
868
clipman->HistoryItems = MAXHISTORY;
869
if (clipman->HistoryItems < MINHISTORY)
870
clipman->HistoryItems = MINHISTORY;
872
if (clipman->MenuCharacters > MAXCHARS)
873
clipman->MenuCharacters = MAXCHARS;
874
if (clipman->MenuCharacters < MINCHARS)
875
clipman->MenuCharacters = MINCHARS;
879
if (!clipman->ExitSave)
882
/* Restore the history */
883
DBG("Restoring the clipboard");
884
file = xfce_resource_save_location (XFCE_RESOURCE_CACHE, "xfce4/clipman/textsrc", FALSE);
885
keyfile = g_key_file_new ();
886
if (g_key_file_load_from_file (keyfile, file, G_KEY_FILE_NONE, NULL))
888
texts = g_key_file_get_string_list (keyfile, "texts", "texts", NULL, NULL);
889
for (i = 0; texts != NULL && texts[i] != NULL && i < clipman->HistoryItems; i++)
890
clipman_add_clip (clipman, texts[i], DEFAULT, RAWTEXT);
893
g_key_file_free (keyfile);
897
file = xfce_resource_save_location (XFCE_RESOURCE_CACHE, "xfce4/clipman/image.png", FALSE);
898
image = gdk_pixbuf_new_from_file (file, NULL);
903
clipman_add_clip (clipman, image, DEFAULT, IMAGE);
904
g_object_unref (image);
907
clipman->DefaultIndex = -1;
908
clipman->PrimaryIndex = -1;
911
static ClipmanPlugin *
912
clipman_new (XfcePanelPlugin *plugin)
914
ClipmanPlugin *clipman;
915
clipman = panel_slice_new0 (ClipmanPlugin);
917
clipman->clips = g_ptr_array_new ();
918
clipman->plugin = plugin;
920
clipman->tooltip = gtk_tooltips_new ();
921
g_object_ref (G_OBJECT (clipman->tooltip));
923
clipman->DefaultIndex=-1;
924
clipman->PrimaryIndex=-1;
926
/* Load Settings, and possibly Data */
927
clipman_read (clipman);
929
/* Create panel widgets */
930
clipman->button = xfce_create_panel_toggle_button ();
931
gtk_widget_show (clipman->button);
933
clipman->icon = gtk_image_new ();
934
gtk_widget_show (clipman->icon);
935
gtk_container_add (GTK_CONTAINER (clipman->button), clipman->icon);
937
gtk_tooltips_set_tip (GTK_TOOLTIPS(clipman->tooltip),
938
clipman->button, _("Clipboard Manager"),
941
g_signal_connect(clipman->button, "button_press_event",
942
G_CALLBACK(clipman_icon_clicked), clipman);
944
/* Start the clipman_timed_poll function */
945
/* TODO Run the timeout only if the plugin takes care of the selections */
946
clipman->TimeoutId = g_timeout_add_full(G_PRIORITY_LOW,
948
(GSourceFunc) clipman_timed_poll,
950
(GDestroyNotify) clipman_reset_timeout);
952
/* Connect to the clipboards */
953
defaultClip = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
954
primaryClip = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
956
/* Respond to clipboard events - rather than polling twice a second */
957
g_signal_connect(G_OBJECT(defaultClip), "owner-change", G_CALLBACK(clipboard_changed), clipman);
958
g_signal_connect(G_OBJECT(primaryClip), "owner-change", G_CALLBACK(clipboard_changed), clipman);
964
clipman_free (XfcePanelPlugin *plugin,
965
ClipmanPlugin *clipman)
972
- primaryClip and defaultClip should be cleared, but gtk
973
takes care about this
976
/* Free the clipboards */
977
gtk_clipboard_clear (primaryClip);
978
gtk_clipboard_clear (defaultClip);
980
/* Destroy the setting dialog, if this open */
981
dialog = g_object_get_data (G_OBJECT (plugin), "dialog");
984
gtk_widget_destroy (dialog);
986
/* Stop the check loop */
987
clipman->killTimeout = TRUE;
988
if (clipman->TimeoutId != 0)
990
g_source_remove(clipman->TimeoutId);
991
clipman->TimeoutId = 0;
994
/* Remove clipboard items */
995
for (i=(gint)clipman->clips->len-1; i>=0; i--)
997
clip = g_ptr_array_index (clipman->clips, i);
998
g_ptr_array_remove_fast (clipman->clips, clip);
999
clipman_free_clip (clip);
1001
g_ptr_array_free (clipman->clips, TRUE);
1003
gtk_tooltips_set_tip (clipman->tooltip, clipman->button, NULL, NULL);
1004
g_object_unref (G_OBJECT (clipman->tooltip));
1006
gtk_widget_destroy (clipman->icon);
1007
gtk_widget_destroy (clipman->button);
1009
clipman->plugin = NULL;
1011
DBG ("Plugin Freed");
1013
panel_slice_free (ClipmanPlugin, clipman);
1017
clipman_set_size (XfcePanelPlugin *plugin,
1019
ClipmanPlugin *clipman)
1024
gtk_widget_set_size_request (clipman->button, wsize, wsize);
1026
size = wsize - 2 - (2 * MAX (clipman->button->style->xthickness,
1027
clipman->button->style->ythickness));
1029
DBG("Set clipman button size to %dpx, load icon at %dpx", wsize, size);
1031
pb = xfce_themed_icon_load ("gtk-paste", size);
1032
gtk_image_set_from_pixbuf (GTK_IMAGE (clipman->icon), pb);
1033
g_object_unref (G_OBJECT (pb));
1039
clipman_construct (XfcePanelPlugin *plugin)
1041
ClipmanPlugin *clipman;
1043
xfce_textdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
1045
clipman = clipman_new (plugin);
1047
gtk_container_add (GTK_CONTAINER (plugin), clipman->button);
1049
xfce_panel_plugin_add_action_widget (plugin, clipman->button);
1051
g_signal_connect (plugin, "free-data",
1052
G_CALLBACK (clipman_free), clipman);
1054
g_signal_connect (plugin, "save",
1055
G_CALLBACK (clipman_save), clipman);
1057
g_signal_connect (plugin, "size-changed",
1058
G_CALLBACK (clipman_set_size), clipman);
1060
xfce_panel_plugin_menu_show_configure (plugin);
1061
g_signal_connect (plugin, "configure-plugin",
1062
G_CALLBACK (clipman_configure), clipman);