2
* Copyright (C) 2004-2006 Jean-Yves Lefort <jylefort@brutele.be>
3
* Copyright (C) 2004-2008 Jean-Yves Lefort <jylefort@brutele.be>
4
5
* This program is free software; you can redistribute it and/or modify
5
6
* it under the terms of the GNU General Public License as published by
6
* the Free Software Foundation; either version 2 of the License, or
7
* the Free Software Foundation; either version 3 of the License, or
7
8
* (at your option) any later version.
9
10
* This program is distributed in the hope that it will be useful,
11
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
13
* GNU General Public License for more details.
14
* You should have received a copy of the GNU General Public License
15
* along with this program; if not, write to the Free Software
16
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15
* You should have received a copy of the GNU General Public License along
16
* with this program; if not, write to the Free Software Foundation, Inc.,
17
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
21
#include <gtk/gtk.h>
23
22
#include "lm-applet.h"
26
#include <glib/gi18n.h>
27
#include "lm-cell-renderer-color.h"
28
#include "lm-host-frontend.h"
28
29
#include "lm-util.h"
39
CLIPBOARD_TARGET_NATIVE,
43
#define CLIPBOARD_TARGET_NATIVE_NAME "x-special/link-monitor-applet-hosts"
45
static GdkAtom clipboard_target_native_atom;
37
47
static GtkClipboard *global_clipboard;
49
59
private GtkWidget *cut_item;
50
60
private GtkWidget *copy_item;
51
61
private GtkWidget *paste_item;
62
private GtkWidget *select_all_item;
52
64
private int add_pending_count;
53
65
private GtkTreeIter add_pending_iter;
67
public gboolean editing_host;
68
property BOOLEAN editing_host (link, export);
55
70
public gboolean can_go_up;
56
71
property BOOLEAN can_go_up (link, export);
58
73
public gboolean can_go_down;
59
74
property BOOLEAN can_go_down (link, export);
76
private GtkWidget *color_dialog destroywith gtk_widget_destroy;
77
private GtkTreeRowReference *color_dialog_row_reference;
63
81
GtkBindingSet *binding_set;
65
83
global_clipboard = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
85
clipboard_target_native_atom = gdk_atom_intern(CLIPBOARD_TARGET_NATIVE_NAME, FALSE);
67
87
binding_set = gtk_binding_set_by_class(class);
69
89
/* Delete removes a row */
81
101
gtk_binding_entry_add_signal(binding_set, GDK_Insert, GDK_SHIFT_MASK, "activate-paste", 0);
84
override (G:Object) GObject *
85
constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_params)
89
106
GtkMenuShell *shell;
90
107
GtkWidget *add_item;
91
GtkWidget *select_all_item;
92
108
GtkListStore *store;
93
109
GtkCellRenderer *renderer;
94
110
GtkTreeViewColumn *column;
95
111
GtkTreeSelection *selection;
98
object = PARENT_HANDLER(type, n_construct_properties, construct_params);
101
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self), FALSE);
102
114
gtk_tree_view_set_reorderable(GTK_TREE_VIEW(self), TRUE);
103
115
gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(self), self_search_equal_cb, NULL, NULL);
114
126
selfp->copy_item = lm_menu_shell_append(shell, GTK_STOCK_COPY, NULL);
115
127
selfp->paste_item = lm_menu_shell_append(shell, GTK_STOCK_PASTE, NULL);
116
128
lm_menu_shell_append(shell, NULL, NULL);
117
select_all_item = lm_menu_shell_append(shell, LM_STOCK_SELECT_ALL, NULL);
129
selfp->select_all_item = lm_menu_shell_append(shell, GTK_STOCK_SELECT_ALL, NULL);
119
131
g_signal_connect_swapped(add_item, "activate", G_CALLBACK(self_activate_add), self);
120
132
g_signal_connect_swapped(selfp->remove_item, "activate", G_CALLBACK(self_activate_remove), self);
123
135
g_signal_connect_swapped(selfp->cut_item, "activate", G_CALLBACK(self_activate_cut), self);
124
136
g_signal_connect_swapped(selfp->copy_item, "activate", G_CALLBACK(self_activate_copy), self);
125
137
g_signal_connect_swapped(selfp->paste_item, "activate", G_CALLBACK(self_activate_paste), self);
126
g_signal_connect(select_all_item, "activate", G_CALLBACK(self_select_all_activate_h), self);
138
g_signal_connect(selfp->select_all_item, "activate", G_CALLBACK(self_select_all_activate_h), self);
128
store = gtk_list_store_new(N_COLUMNS, LM_TYPE_HOST, G_TYPE_STRING);
140
store = gtk_list_store_new(N_COLUMNS,
141
LM_TYPE_HOST_FRONTEND,
129
144
gtk_tree_view_set_model(GTK_TREE_VIEW(self), GTK_TREE_MODEL(store));
146
renderer = lm_cell_renderer_color_new();
147
g_signal_connect(renderer, "activated", G_CALLBACK(self_color_activated_h), self);
149
column = gtk_tree_view_column_new_with_attributes(_("Color"),
151
"color", COLUMN_COLOR,
153
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
154
gtk_tree_view_append_column(GTK_TREE_VIEW(self), column);
131
156
renderer = gtk_cell_renderer_text_new();
132
157
g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
133
158
g_object_connect(renderer,
159
"signal::editing-started", self_editing_started_h, self,
134
160
"signal::editing-canceled", self_editing_canceled_h, self,
135
161
"signal::edited", self_edited_h, self,
146
173
g_signal_connect(selection, "changed", G_CALLBACK(self_selection_changed_h), self);
149
LM_LIST_FOREACH(l, selfp->applet->hosts)
176
LM_ARRAY_FOREACH(i, selfp->applet->hosts)
151
LMHost *host = l->data;
178
LMHostFrontend *host = g_ptr_array_index(selfp->applet->hosts, i);
152
179
GtkTreeIter iter;
154
181
gtk_list_store_insert_with_values(store, &iter,
156
183
COLUMN_HOST, host,
157
COLUMN_NAME, host->name,
184
COLUMN_COLOR, &host->color,
185
COLUMN_NAME, LM_HOST(host)->name,
162
g_signal_connect_swapped(store, "row-deleted", G_CALLBACK(self_reorder), self);
189
g_object_connect(store,
190
/* for the sensitivity of "Select All" */
191
"swapped-signal::row-inserted", self_update_sensitivity, self,
192
"swapped-signal::row-deleted", self_update_sensitivity, self,
194
"swapped-signal::row-deleted", self_reorder, self,
164
197
g_object_unref(store);
246
277
selfp->add_pending_count++;
248
279
path = gtk_tree_model_get_path(model, &selfp->add_pending_iter);
249
column = gtk_tree_view_get_column(GTK_TREE_VIEW(self), 0);
280
column = gtk_tree_view_get_column(GTK_TREE_VIEW(self), 1);
251
282
gtk_widget_grab_focus(GTK_WIDGET(self));
252
283
gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(self), path, column, FALSE, 0, 0);
289
320
if (gtk_tree_model_get_iter(model, &other_iter, path))
322
LMHostFrontend *host;
323
LMHostFrontend *other_host;
294
325
gtk_tree_model_get(model, &iter, COLUMN_HOST, &host, -1);
295
326
gtk_tree_model_get(model, &other_iter, COLUMN_HOST, &other_host, -1);
327
358
LM_LIST_FOREACH(l, references)
329
360
GtkTreeRowReference *reference = l->data;
331
361
GtkTreeIter iter;
335
path = gtk_tree_row_reference_get_path(reference);
336
status = gtk_tree_model_get_iter(model, &iter, path);
363
LMHostFrontend *host;
365
/* if the color dialog is associated with the host, destroy it */
366
if (selfp->color_dialog_row_reference
367
&& ! lm_tree_row_reference_compare(reference,
368
selfp->color_dialog_row_reference))
369
gtk_widget_destroy(selfp->color_dialog);
371
status = lm_tree_row_reference_get_iter(reference, &iter);
337
372
g_assert(status == TRUE);
338
gtk_tree_path_free(path);
340
374
gtk_tree_model_get(model, &iter, COLUMN_HOST, &host, -1);
352
386
copy_selected_hosts (self)
388
GSList *host_configs = NULL;
355
389
GtkTreeModel *model;
356
390
GSList *references;
393
static const GtkTargetEntry init_target_table[] = {
394
{ CLIPBOARD_TARGET_NATIVE_NAME, 0, CLIPBOARD_TARGET_NATIVE }
396
GtkTargetList *target_list;
397
GtkTargetEntry *target_table;
398
int target_table_len;
359
string = g_string_new(NULL);
360
400
model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
361
402
references = self_get_selected_rows(self);
362
403
LM_LIST_FOREACH(l, references)
364
405
GtkTreeRowReference *reference = l->data;
365
406
GtkTreePath *path;
366
407
GtkTreeIter iter;
408
LMHostFrontend *host;
370
410
path = gtk_tree_row_reference_get_path(reference);
371
411
status = gtk_tree_model_get_iter(model, &iter, path);
373
413
gtk_tree_path_free(path);
375
415
gtk_tree_model_get(model, &iter, COLUMN_HOST, &host, -1);
378
g_string_append_c(string, '\n');
379
g_string_append(string, host->name);
416
host_configs = g_slist_append(host_configs, lm_host_frontend_get_configuration(host));
381
417
g_object_unref(host);
382
419
gtk_tree_row_reference_free(reference);
384
421
g_slist_free(references);
386
gtk_clipboard_set_text(global_clipboard, string->str, -1);
387
g_string_free(string, TRUE);
423
target_list = gtk_target_list_new(init_target_table, G_N_ELEMENTS(init_target_table));
424
gtk_target_list_add_text_targets(target_list, CLIPBOARD_TARGET_TEXT);
426
target_table = gtk_target_table_new_from_list(target_list, &target_table_len);
427
gtk_target_list_unref(target_list);
429
status = gtk_clipboard_set_with_data(global_clipboard,
432
self_get_clipboard_cb,
433
self_clear_clipboard_cb,
435
g_assert(status == TRUE);
437
gtk_target_table_free(target_table, target_table_len);
441
get_clipboard_cb (GtkClipboard *clipboard,
442
GtkSelectionData *selection_data,
444
gpointer user_data_or_owner)
446
GSList *host_configs = user_data_or_owner;
449
switch ((ClipboardTarget) info)
451
case CLIPBOARD_TARGET_NATIVE:
452
gtk_selection_data_set(selection_data,
453
clipboard_target_native_atom,
455
(unsigned char *) &host_configs,
456
sizeof(host_configs));
459
case CLIPBOARD_TARGET_TEXT:
463
str = g_string_new(NULL);
465
LM_LIST_FOREACH(l, host_configs)
467
LMHostFrontendConfiguration *config = l->data;
469
g_string_append(str, config->name);
472
g_string_append_c(str, '\n');
475
gtk_selection_data_set_text(selection_data, str->str, str->len);
476
g_string_free(str, TRUE);
481
g_assert_not_reached();
487
clear_clipboard_cb (GtkClipboard *clipboard, gpointer user_data_or_owner)
489
GSList *host_configs = user_data_or_owner;
491
lm_g_slist_free_deep_custom(host_configs, (GFunc) lm_host_frontend_configuration_free, NULL);
390
494
signal (ACTION) private NONE (NONE)
403
507
signal (ACTION) private NONE (NONE)
404
508
void activate_paste (self)
510
GtkSelectionData *data;
513
data = gtk_clipboard_wait_for_contents(global_clipboard, clipboard_target_native_atom);
516
GSList *host_configs;
519
memcpy(&host_configs, data->data, data->length);
521
LM_LIST_FOREACH(l, host_configs)
523
LMHostFrontendConfiguration *config = l->data;
524
LMHostFrontend *host;
526
host = lm_host_frontend_new_from_configuration(selfp->applet, config);
527
self_add_host(self, host);
528
g_object_unref(host);
531
gtk_selection_data_free(data);
411
535
text = gtk_clipboard_wait_for_text(global_clipboard);
412
g_assert(text != NULL);
414
hosts = g_strsplit(text, "\n", 0);
417
model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
418
for (i = 0; hosts[i]; i++)
423
host = lm_applet_add_host(selfp->applet, hosts[i]);
425
gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter,
428
COLUMN_NAME, hosts[i],
541
hosts = g_strsplit(text, "\n", 0);
544
for (i = 0; hosts[i]; i++)
546
LMHostFrontend *host;
548
host = lm_host_frontend_new(selfp->applet, hosts[i], NULL);
549
self_add_host(self, host);
550
g_object_unref(host);
558
add_host (self, LM:Host:Frontend *host (check null type))
563
lm_applet_add_host(selfp->applet, host);
565
model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
567
gtk_list_store_insert_with_values(GTK_LIST_STORE(model), &iter,
570
COLUMN_COLOR, &host->color,
571
COLUMN_NAME, LM_HOST(host)->name,
585
color_activated_h (LMCellRendererColor *renderer,
589
Self *self = user_data;
593
LMHostFrontend *host;
594
GtkWindow *parent_window;
596
if (! selfp->color_dialog)
598
selfp->color_dialog = gtk_color_selection_dialog_new(_("Pick a Color"));
600
g_object_weak_ref(G_OBJECT(selfp->color_dialog), self_color_dialog_weak_notify_cb, self);
602
g_signal_connect(selfp->color_dialog, "response", G_CALLBACK(self_color_dialog_response_h), self);
605
model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
607
status = gtk_tree_model_get_iter_from_string(model, &iter, path);
608
g_assert(status == TRUE);
610
gtk_tree_model_get(model, &iter, COLUMN_HOST, &host, -1);
611
gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(selfp->color_dialog)->colorsel), &host->color);
612
g_object_unref(host);
614
gtk_tree_row_reference_free(selfp->color_dialog_row_reference);
615
selfp->color_dialog_row_reference = lm_tree_row_reference_new_from_path_string(model, path);
617
parent_window = lm_widget_get_parent_window(GTK_WIDGET(self));
620
if (parent_window != gtk_window_get_transient_for(GTK_WINDOW(selfp->color_dialog)))
621
gtk_window_set_transient_for(GTK_WINDOW(selfp->color_dialog), parent_window);
623
gtk_window_set_modal(GTK_WINDOW(selfp->color_dialog), gtk_window_get_modal(parent_window));
626
lm_window_present_from_event(GTK_WINDOW(selfp->color_dialog));
630
color_dialog_response_h (GtkDialog *dialog,
634
Self *self = user_data;
636
if (response == GTK_RESPONSE_OK)
642
LMHostFrontend *host;
644
gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dialog)->colorsel), &color);
646
model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
648
status = lm_tree_row_reference_get_iter(selfp->color_dialog_row_reference, &iter);
649
g_assert(status == TRUE);
651
gtk_tree_model_get(model, &iter, COLUMN_HOST, &host, -1);
652
lm_host_frontend_set_color(host, &color);
653
g_object_unref(host);
655
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
656
COLUMN_COLOR, &color,
660
gtk_widget_destroy(GTK_WIDGET(dialog));
664
color_dialog_weak_notify_cb (gpointer data, GObject *former_dialog)
668
selfp->color_dialog = NULL;
670
gtk_tree_row_reference_free(selfp->color_dialog_row_reference);
671
selfp->color_dialog_row_reference = NULL;
675
editing_started_h (GtkCellRenderer *renderer,
676
GtkCellEditable *editable,
680
Self *self = user_data;
682
self_set_editing_host(self, TRUE);
444
686
editing_canceled_h (GtkCellRenderer *renderer,
445
687
gpointer user_data)
447
689
Self *self = user_data;
691
self_set_editing_host(self, FALSE);
449
693
if (selfp->add_pending_count)
451
695
GtkTreeModel *model;
465
709
Self *self = user_data;
466
710
GtkTreeModel *model;
468
712
GtkTreeIter iter;
713
LMHostFrontend *old_host;
714
LMHostFrontend *new_host;
716
self_set_editing_host(self, FALSE);
472
718
model = gtk_tree_view_get_model(GTK_TREE_VIEW(self));
473
path = gtk_tree_path_new_from_string(path_string);
474
gtk_tree_model_get_iter(model, &iter, path);
475
gtk_tree_path_free(path);
719
status = gtk_tree_model_get_iter_from_string(model, &iter, path_string);
720
g_assert(status == TRUE);
477
722
gtk_tree_model_get(model, &iter, COLUMN_HOST, &old_host, -1);
481
host = lm_applet_replace_host(selfp->applet, old_host, new_text);
726
new_host = lm_host_frontend_new(selfp->applet, new_text, &old_host->color);
727
lm_applet_replace_host(selfp->applet, old_host, new_host);
482
728
g_object_unref(old_host);
485
host = lm_applet_add_host(selfp->applet, new_text);
732
new_host = lm_host_frontend_new(selfp->applet, new_text, NULL);
733
lm_applet_add_host(selfp->applet, new_host);
487
736
gtk_list_store_set(GTK_LIST_STORE(model), &iter,
489
COLUMN_NAME, new_text,
737
COLUMN_HOST, new_host,
738
COLUMN_COLOR, &new_host->color,
739
COLUMN_NAME, LM_HOST(new_host)->name,
742
g_object_unref(new_host);
492
744
if (selfp->add_pending_count)
493
745
selfp->add_pending_count--;
547
800
gtk_widget_set_sensitive(selfp->copy_item, has_selection);
548
801
gtk_widget_set_sensitive(selfp->up_item, has_prev);
549
802
gtk_widget_set_sensitive(selfp->down_item, has_next);
804
has_hosts = gtk_tree_model_get_iter_first(model, &iter);
805
gtk_widget_set_sensitive(selfp->select_all_item, has_hosts);
553
popup_menu (self, unsigned int button, guint32 activate_time)
809
popup_menu (self, int button, guint32 activate_time)
555
gtk_widget_set_sensitive(selfp->paste_item, gtk_clipboard_wait_is_text_available(global_clipboard));
813
gtk_widget_set_sensitive(selfp->paste_item, FALSE);
815
/* do not crash if self is finalized before the request completes */
816
self_box = g_new(Self *, 1);
818
lm_add_weak_pointer(self_box);
820
gtk_clipboard_request_targets(global_clipboard, self_popup_menu_targets_received_cb, self_box);
556
822
gtk_menu_popup(GTK_MENU(selfp->menu), NULL, NULL, NULL, NULL, button, activate_time);
826
popup_menu_targets_received_cb (GtkClipboard *clipboard,
831
Self **self_box = data;
832
Self *self = *self_box;
837
gtk_widget_set_sensitive(selfp->paste_item, self_can_paste(atoms, n_atoms));
839
lm_remove_weak_pointer(self_box);
846
can_paste (GdkAtom *atoms, int n_atoms)
850
for (i = 0; i < n_atoms; i++)
851
if (atoms[i] == CLIPBOARD_TARGET_NATIVE)
854
return gtk_targets_include_text(atoms, n_atoms);
560
858
popup_menu_h (GtkWidget *widget, gpointer user_data)