1 /* vi:set sw=2 sts=2 ts=2 et ai tw=100: */
2 /*-
3 * Copyright (c) 2008 Stephan Arts <stephan@xfce.org>
4 * Copyright (c) 2008 Jannis Pohlmann <jannis@xfce.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #ifdef HAVE_STDLIB_H
27 #include <stdlib.h>
28 #endif
29
30 #ifdef HAVE_STRING_H
31 #include <string.h>
32 #endif
33
34 #include <glib.h>
35 #include <glib-object.h>
36
37 #include <gdk/gdk.h>
38 #include <gdk/gdkx.h>
39 #include <gtk/gtk.h>
40 #include <gtk/gtkx.h>
41
42 #include <libxfce4util/libxfce4util.h>
43 #include <libxfce4ui/libxfce4ui.h>
44 #include <xfconf/xfconf.h>
45 #include <libxfce4kbd-private/xfce-shortcut-dialog.h>
46 #include <libxfce4kbd-private/xfce-shortcuts-provider.h>
47 #include <libxfce4kbd-private/xfce-shortcuts-xfwm4.h>
48
49 #include <common/xfwm-common.h>
50
51 #include "xfwm4-dialog_ui.h"
52 #include "xfwm4-settings.h"
53 #include "range-debouncer.h"
54
55
56
57 #define DEFAULT_THEME "Greybird"
58
59 #define SHORTCUTS_NAME_COLUMN 0
60 #define SHORTCUTS_FEATURE_COLUMN 1
61 #define SHORTCUTS_SHORTCUT_COLUMN 2
62 #define SHORTCUTS_SHORTCUT_LABEL_COLUMN 3
63
64
65
66 typedef struct _MenuTemplate MenuTemplate;
67
68
69
70 /* Property identifiers */
71 enum
72 {
73 PROP_0,
74 PROP_GTK_BUILDER,
75 };
76
77
78
79 static void xfwm_settings_constructed (GObject *object);
80 static void xfwm_settings_finalize (GObject *object);
81 static void xfwm_settings_get_property (GObject *object,
82 guint prop_id,
83 GValue *value,
84 GParamSpec *pspec);
85 static void xfwm_settings_set_property (GObject *object,
86 guint prop_id,
87 const GValue *value,
88 GParamSpec *pspec);
89 static gint xfwm_settings_theme_sort_func (GtkTreeModel *model,
90 GtkTreeIter *iter1,
91 GtkTreeIter *iter2,
92 gpointer data);
93 static void xfwm_settings_load_themes (XfwmSettings *settings);
94 static void xfwm_settings_theme_selection_changed (GtkTreeSelection *selection,
95 XfwmSettings *settings);
96 static void xfwm_settings_title_alignment_changed (GtkComboBox *combo,
97 XfwmSettings *settings);
98 static void xfwm_settings_active_frame_drag_data (GtkWidget *widget,
99 GdkDragContext *drag_context,
100 gint x,
101 gint y,
102 GtkSelectionData *data,
103 guint info,
104 guint time,
105 XfwmSettings *settings);
106 static gboolean xfwm_settings_active_frame_drag_motion (GtkWidget *widget,
107 GdkDragContext *drag_context,
108 gint x,
109 gint y,
110 guint time,
111 XfwmSettings *settings);
112 static void xfwm_settings_active_frame_drag_leave (GtkWidget *widget,
113 GdkDragContext *drag_context,
114 guint time,
115 XfwmSettings *settings);
116 static void xfwm_settings_hidden_frame_drag_data (GtkWidget *widget,
117 GdkDragContext *drag_context,
118 gint x,
119 gint y,
120 GtkSelectionData *data,
121 guint info,
122 guint timestamp,
123 XfwmSettings *settings);
124 static gboolean xfwm_settings_title_button_press_event (GtkWidget *widget);
125 static void xfwm_settings_title_button_drag_data (GtkWidget *widget,
126 GdkDragContext *drag_context,
127 GtkSelectionData *data,
128 guint info,
129 guint timestamp);
130 static void xfwm_settings_title_button_drag_begin (GtkWidget *widget,
131 GdkDragContext *drag_context);
132 static void xfwm_settings_title_button_drag_end (GtkWidget *widget,
133 GdkDragContext *drag_context);
134 static gboolean xfwm_settings_active_frame_draw (GtkWidget *widget,
135 cairo_t *cr,
136 XfwmSettings *settings);
137 static gboolean xfwm_settings_signal_blocker (GtkWidget *widget);
138
139 /* FIXME! */
140 #if 0
141 static GdkPixbuf *xfwm_settings_create_icon_from_widget (GtkWidget *widget);
142 #endif
143
144 static void xfwm_settings_save_button_layout (XfwmSettings *settings,
145 GtkContainer *container);
146 static void xfwm_settings_double_click_action_changed (GtkComboBox *combo,
147 XfwmSettings *settings);
148 static void xfwm_settings_title_button_alignment_changed (GtkComboBox *combo,
149 GtkWidget *button);
150
151 static void xfwm_settings_button_layout_property_changed (XfconfChannel *channel,
152 const gchar *property,
153 const GValue *value,
154 XfwmSettings *settings);
155 static void xfwm_settings_title_alignment_property_changed (XfconfChannel *channel,
156 const gchar *property,
157 const GValue *value,
158 XfwmSettings *settings);
159 static void xfwm_settings_double_click_action_property_changed (XfconfChannel *channel,
160 const gchar *property,
161 const GValue *value,
162 XfwmSettings *settings);
163 static void xfwm_settings_click_to_focus_property_changed (XfconfChannel *channel,
164 const gchar *property,
165 const GValue *value,
166 XfwmSettings *settings);
167 static void xfwm_settings_initialize_shortcuts (XfwmSettings *settings);
168 static void xfwm_settings_reload_shortcuts (XfwmSettings *settings);
169 static void xfwm_settings_shortcut_added (XfceShortcutsProvider *provider,
170 const gchar *shortcut,
171 XfwmSettings *settings);
172 static void xfwm_settings_shortcut_removed (XfceShortcutsProvider *provider,
173 const gchar *shortcut,
174 XfwmSettings *settings);
175 static gboolean xfwm_settings_update_treeview_on_conflict_replace (GtkTreeModel *model,
176 GtkTreePath *path,
177 GtkTreeIter *iter,
178 gpointer shortcut_to_erase);
179 static void xfwm_settings_shortcut_edit_clicked (GtkButton *button,
180 XfwmSettings *settings);
181 static void xfwm_settings_shortcut_clear_clicked (GtkButton *button,
182 XfwmSettings *settings);
183 static void xfwm_settings_shortcut_reset_clicked (GtkButton *button,
184 XfwmSettings *settings);
185 static void xfwm_settings_shortcut_row_activated (GtkTreeView *tree_view,
186 GtkTreePath *path,
187 GtkTreeViewColumn *column,
188 XfwmSettings *settings);
189
190
191
192 struct _XfwmSettingsPrivate
193 {
194 GtkBuilder *builder;
195 XfceShortcutsProvider *provider;
196 XfconfChannel *wm_channel;
197 };
198
199 G_DEFINE_TYPE_WITH_PRIVATE (XfwmSettings, xfwm_settings, G_TYPE_OBJECT)
200
201 struct _MenuTemplate
202 {
203 const gchar *name;
204 const gchar *value;
205 };
206
207 enum
208 {
209 COL_THEME_NAME,
210 COL_THEME_RC,
211 N_COLUMNS
212 };
213
214
215 static const MenuTemplate double_click_values[] = {
216 { N_("Shade window"), "shade" },
217 { N_("Hide window"), "hide" },
218 { N_("Maximize window"), "maximize" },
219 { N_("Fill window"), "fill" },
220 { N_("Always on top"), "above" },
221 { N_("Nothing"), "none" },
222 { NULL, NULL }
223 };
224
225 static const MenuTemplate title_align_values[] = {
226 { N_("Left"), "left" },
227 { N_("Center"), "center" },
228 { N_("Right"), "right" },
229 { NULL, NULL },
230 };
231
232
233
234 static gboolean opt_version = FALSE;
235 static Window opt_socket_id = 0;
236 static GOptionEntry opt_entries[] = {
237 { "socket-id", 's', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_INT, &opt_socket_id,
238 N_("Settings manager socket"), N_("SOCKET ID") },
239 { "version", 'V', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_version,
240 N_("Version information"), NULL },
241 { NULL }
242 };
243
244
245
246 static void
xfwm_settings_class_init(XfwmSettingsClass * klass)247 xfwm_settings_class_init (XfwmSettingsClass *klass)
248 {
249 GObjectClass *gobject_class;
250
251 gobject_class = G_OBJECT_CLASS (klass);
252 gobject_class->constructed = xfwm_settings_constructed;
253 gobject_class->finalize = xfwm_settings_finalize;
254 gobject_class->get_property = xfwm_settings_get_property;
255 gobject_class->set_property = xfwm_settings_set_property;
256
257 g_object_class_install_property (gobject_class,
258 PROP_GTK_BUILDER,
259 g_param_spec_object ("gtk-builder",
260 "gtk-builder",
261 "gtk-builder",
262 GTK_TYPE_BUILDER,
263 G_PARAM_CONSTRUCT_ONLY |
264 G_PARAM_WRITABLE));
265 }
266
267
268
269 static void
xfwm_settings_init(XfwmSettings * settings)270 xfwm_settings_init (XfwmSettings *settings)
271 {
272 settings->priv = xfwm_settings_get_instance_private (settings);
273
274 settings->priv->builder = NULL;
275 settings->priv->provider = xfce_shortcuts_provider_new ("xfwm4");
276 settings->priv->wm_channel = xfconf_channel_new ("xfwm4");
277 }
278
279
280
281 static void
xfwm_settings_constructed(GObject * object)282 xfwm_settings_constructed (GObject *object)
283 {
284 XfwmSettings *settings = XFWM_SETTINGS (object);
285 const MenuTemplate *template;
286 GtkTreeSelection *selection;
287 GtkCellRenderer *renderer;
288 GtkTargetEntry target_entry[2];
289 GtkListStore *list_store;
290 GtkTreeIter iter;
291 GtkWidget *theme_name_treeview;
292 GtkWidget *title_font_button;
293 GtkWidget *title_align_combo;
294 GtkWidget *active_frame;
295 GtkWidget *active_box;
296 GtkWidget *hidden_frame;
297 GtkWidget *hidden_box;
298 GtkWidget *shortcuts_treeview;
299 GtkWidget *shortcuts_edit_button;
300 GtkWidget *shortcuts_clear_button;
301 GtkWidget *shortcuts_reset_button;
302 GtkWidget *focus_delay_scale;
303 GtkWidget *focus_raise_delay_scale;
304 GtkWidget *raise_on_click_check;
305 GtkWidget *raise_on_focus_check;
306 GtkWidget *click_to_focus_radio;
307 GtkWidget *focus_new_check;
308 GtkWidget *box_move_check;
309 GtkWidget *box_resize_check;
310 GtkWidget *wrap_workspaces_check;
311 GtkWidget *wrap_windows_check;
312 GtkWidget *snap_to_border_check;
313 GtkWidget *snap_to_window_check;
314 GtkWidget *double_click_action_combo;
315 GtkWidget *snap_width_scale;
316 GtkWidget *wrap_resistance_scale;
317 GtkWidget *button;
318 GValue value = { 0, };
319 GList *children;
320 GList *list_iter;
321 const gchar *name;
322
323 /* Style tab widgets */
324 theme_name_treeview = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "theme_name_treeview"));
325 title_font_button = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "title_font_button"));
326 title_align_combo = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "title_align_combo"));
327 active_frame = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "active-frame"));
328 active_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "active-box"));
329 hidden_frame = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "hidden-frame"));
330 hidden_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "hidden-box"));
331
332 /* Style tab: theme name */
333 {
334 list_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING);
335 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (list_store), COL_THEME_NAME,
336 (GtkTreeIterCompareFunc) xfwm_settings_theme_sort_func,
337 NULL, NULL);
338 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (list_store), COL_THEME_NAME, GTK_SORT_ASCENDING);
339 gtk_tree_view_set_model (GTK_TREE_VIEW (theme_name_treeview), GTK_TREE_MODEL (list_store));
340 g_object_unref (G_OBJECT (list_store));
341
342 renderer = gtk_cell_renderer_text_new ();
343 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (theme_name_treeview),
344 0, _("Theme"), renderer, "text", 0, NULL);
345
346 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (theme_name_treeview));
347 g_signal_connect (selection, "changed", G_CALLBACK (xfwm_settings_theme_selection_changed),
348 settings);
349 gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
350
351 xfwm_settings_load_themes (settings);
352 }
353
354 /* Style tab: font */
355 xfconf_g_property_bind (settings->priv->wm_channel, "/general/title_font", G_TYPE_STRING,
356 title_font_button, "font-name");
357
358 /* Style tab: title alignment */
359 {
360 gtk_cell_layout_clear (GTK_CELL_LAYOUT (title_align_combo));
361
362 renderer = gtk_cell_renderer_text_new ();
363 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (title_align_combo), renderer, TRUE);
364 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (title_align_combo), renderer, "text", 0);
365
366 list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
367 gtk_combo_box_set_model (GTK_COMBO_BOX (title_align_combo), GTK_TREE_MODEL (list_store));
368
369 for (template = title_align_values; template->name != NULL; ++template)
370 {
371 gtk_list_store_append (list_store, &iter);
372 gtk_list_store_set (list_store, &iter, 0, _(template->name), 1, template->value, -1);
373 }
374 g_object_unref (G_OBJECT (list_store));
375 xfconf_channel_get_property (settings->priv->wm_channel, "/general/title_alignment", &value);
376 xfwm_settings_title_alignment_property_changed (settings->priv->wm_channel,
377 "/general/title_alignment", &value, settings);
378 g_value_unset (&value);
379
380 g_signal_connect (title_align_combo, "changed",
381 G_CALLBACK (xfwm_settings_title_alignment_changed), settings);
382 g_signal_connect (settings->priv->wm_channel, "property-changed::/general/title_alignment",
383 G_CALLBACK (xfwm_settings_title_alignment_property_changed), settings);
384 }
385
386 /* Style tab: button layout */
387 {
388 target_entry[0].target = "_xfwm4_button_layout";
389 target_entry[0].flags = 0;
390 target_entry[0].info = 2;
391
392 target_entry[1].target = "_xfwm4_active_layout";
393 target_entry[1].flags = 0;
394 target_entry[1].info = 3;
395
396 gtk_drag_dest_set (active_frame, GTK_DEST_DEFAULT_ALL, target_entry, 2, GDK_ACTION_MOVE);
397
398 g_signal_connect (active_frame, "drag-data-received",
399 G_CALLBACK (xfwm_settings_active_frame_drag_data), settings);
400 g_signal_connect (active_frame, "drag-motion",
401 G_CALLBACK (xfwm_settings_active_frame_drag_motion), settings);
402 g_signal_connect (active_frame, "drag-leave",
403 G_CALLBACK (xfwm_settings_active_frame_drag_leave), settings);
404
405 gtk_drag_dest_set (hidden_frame, GTK_DEST_DEFAULT_ALL, target_entry, 1, GDK_ACTION_MOVE);
406
407 g_signal_connect (hidden_frame, "drag-data-received",
408 G_CALLBACK (xfwm_settings_hidden_frame_drag_data), settings);
409
410 g_object_set_data (G_OBJECT (active_frame), "indicator-position", GINT_TO_POINTER (-1));
411 g_signal_connect (active_frame, "draw",
412 G_CALLBACK (xfwm_settings_active_frame_draw), settings);
413
414 children = gtk_container_get_children (GTK_CONTAINER (active_box));
415 for (list_iter = children; list_iter != NULL; list_iter = g_list_next (list_iter))
416 {
417 button = GTK_WIDGET (list_iter->data);
418 name = gtk_buildable_get_name (GTK_BUILDABLE (button));
419
420 if (name[strlen (name) - 1] == '|')
421 {
422 g_signal_connect (title_align_combo, "changed",
423 G_CALLBACK (xfwm_settings_title_button_alignment_changed), button);
424 xfwm_settings_title_button_alignment_changed (GTK_COMBO_BOX (title_align_combo),
425 button);
426 }
427
428 g_object_set_data (G_OBJECT (button), "key_char", (gpointer) &name[strlen (name) - 1]);
429 gtk_drag_source_set (button, GDK_BUTTON1_MASK, &target_entry[1], 1, GDK_ACTION_MOVE);
430
431 g_signal_connect (button, "drag_data_get",
432 G_CALLBACK (xfwm_settings_title_button_drag_data), NULL);
433 g_signal_connect (button, "drag_begin", G_CALLBACK (xfwm_settings_title_button_drag_begin),
434 NULL);
435 g_signal_connect (button, "drag_end", G_CALLBACK (xfwm_settings_title_button_drag_end),
436 NULL);
437 g_signal_connect (button, "button_press_event",
438 G_CALLBACK (xfwm_settings_title_button_press_event), NULL);
439 g_signal_connect (button, "enter_notify_event",
440 G_CALLBACK (xfwm_settings_signal_blocker), NULL);
441 g_signal_connect (button, "focus", G_CALLBACK (xfwm_settings_signal_blocker), NULL);
442 }
443 g_list_free (children);
444
445 children = gtk_container_get_children (GTK_CONTAINER (hidden_box));
446 for (list_iter = children; list_iter != NULL; list_iter = g_list_next (list_iter))
447 {
448 button = GTK_WIDGET (list_iter->data);
449 name = gtk_buildable_get_name (GTK_BUILDABLE (button));
450
451 g_object_set_data (G_OBJECT (button), "key_char", (gpointer) &name[strlen (name) - 1]);
452 gtk_drag_source_set (button, GDK_BUTTON1_MASK, &target_entry[0], 1, GDK_ACTION_MOVE);
453
454 g_signal_connect (button, "drag_data_get",
455 G_CALLBACK (xfwm_settings_title_button_drag_data), NULL);
456 g_signal_connect (button, "drag_begin", G_CALLBACK (xfwm_settings_title_button_drag_begin),
457 NULL);
458 g_signal_connect (button, "drag_end", G_CALLBACK (xfwm_settings_title_button_drag_end),
459 NULL);
460 g_signal_connect (button, "button_press_event",
461 G_CALLBACK (xfwm_settings_title_button_press_event), NULL);
462 g_signal_connect (button, "enter_notify_event",
463 G_CALLBACK (xfwm_settings_signal_blocker), NULL);
464 g_signal_connect (button, "focus", G_CALLBACK (xfwm_settings_signal_blocker), NULL);
465 }
466 g_list_free (children);
467
468 xfconf_channel_get_property (settings->priv->wm_channel, "/general/button_layout", &value);
469 xfwm_settings_button_layout_property_changed (settings->priv->wm_channel,
470 "/general/button_layout", &value, settings);
471 g_value_unset (&value);
472 }
473
474 /* Keyboard tab widgets */
475 shortcuts_treeview = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "shortcuts_treeview"));
476 shortcuts_edit_button = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
477 "shortcuts_edit_button"));
478 shortcuts_clear_button = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
479 "shortcuts_clear_button"));
480 shortcuts_reset_button = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
481 "shortcuts_reset_button"));
482
483 /* Set reset button icon */
484 gtk_button_set_image (GTK_BUTTON (shortcuts_reset_button),
485 gtk_image_new_from_icon_name ("document-revert",
486 GTK_ICON_SIZE_BUTTON));
487
488 /* Keyboard tab: Shortcuts tree view */
489 {
490 GtkTreeViewColumn * column = NULL;
491 gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (shortcuts_treeview)),
492 GTK_SELECTION_MULTIPLE);
493
494 list_store = gtk_list_store_new (4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
495 gtk_tree_view_set_model (GTK_TREE_VIEW (shortcuts_treeview), GTK_TREE_MODEL (list_store));
496 g_object_unref (G_OBJECT (list_store));
497
498 renderer = gtk_cell_renderer_text_new ();
499 column = gtk_tree_view_column_new_with_attributes (_("Action"), renderer,
500 "text", SHORTCUTS_NAME_COLUMN,
501 NULL);
502 gtk_tree_view_insert_column (GTK_TREE_VIEW (shortcuts_treeview), column, 0);
503 gtk_tree_view_column_set_sort_column_id (column, SHORTCUTS_NAME_COLUMN);
504
505 renderer = gtk_cell_renderer_text_new ();
506 column = gtk_tree_view_column_new_with_attributes (_("Shortcut"), renderer,
507 "text", SHORTCUTS_SHORTCUT_LABEL_COLUMN,
508 NULL);
509 gtk_tree_view_insert_column (GTK_TREE_VIEW (shortcuts_treeview), column, 1);
510 gtk_tree_view_column_set_sort_column_id (column, SHORTCUTS_SHORTCUT_LABEL_COLUMN);
511
512 /* Initial sorting: By category; given by the model */
513
514 g_signal_connect (shortcuts_treeview, "row-activated",
515 G_CALLBACK (xfwm_settings_shortcut_row_activated), settings);
516 }
517
518 /* Connect to shortcut buttons */
519 g_signal_connect (shortcuts_edit_button, "clicked",
520 G_CALLBACK (xfwm_settings_shortcut_edit_clicked), settings);
521 g_signal_connect (shortcuts_clear_button, "clicked",
522 G_CALLBACK (xfwm_settings_shortcut_clear_clicked), settings);
523 g_signal_connect (shortcuts_reset_button, "clicked",
524 G_CALLBACK (xfwm_settings_shortcut_reset_clicked), settings);
525
526 /* Focus tab widgets */
527 focus_delay_scale = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "focus_delay_scale"));
528 focus_raise_delay_scale = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "focus_raise_delay_scale"));
529 focus_new_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "focus_new_check"));
530 raise_on_focus_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "raise_on_focus_check"));
531 raise_on_click_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "raise_on_click_check"));
532 click_to_focus_radio = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "click_to_focus_radio"));
533
534 /* Focus tab */
535 xfconf_g_property_bind (settings->priv->wm_channel, "/general/focus_delay", G_TYPE_INT,
536 range_debouncer_bind (GTK_RANGE (focus_delay_scale)), "value");
537 xfconf_g_property_bind (settings->priv->wm_channel, "/general/raise_delay", G_TYPE_INT,
538 range_debouncer_bind (GTK_RANGE (focus_raise_delay_scale)), "value");
539 xfconf_g_property_bind (settings->priv->wm_channel, "/general/raise_on_click", G_TYPE_BOOLEAN,
540 raise_on_click_check, "active");
541 xfconf_g_property_bind (settings->priv->wm_channel, "/general/raise_on_focus", G_TYPE_BOOLEAN,
542 raise_on_focus_check, "active");
543 xfconf_g_property_bind (settings->priv->wm_channel, "/general/focus_new", G_TYPE_BOOLEAN,
544 focus_new_check, "active");
545 xfconf_g_property_bind (settings->priv->wm_channel, "/general/click_to_focus", G_TYPE_BOOLEAN,
546 click_to_focus_radio, "active");
547
548 g_signal_connect (settings->priv->wm_channel, "property-changed::/general/click_to_focus",
549 G_CALLBACK (xfwm_settings_click_to_focus_property_changed), settings);
550
551 xfconf_channel_get_property (settings->priv->wm_channel, "/general/click_to_focus", &value);
552 xfwm_settings_click_to_focus_property_changed (settings->priv->wm_channel,
553 "/general/click_to_focus", &value, settings);
554 g_value_unset (&value);
555
556 /* Advanced tab widgets */
557 box_move_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "box_move_check"));
558 box_resize_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "box_resize_check"));
559 wrap_workspaces_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
560 "wrap_workspaces_check"));
561 wrap_windows_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "wrap_windows_check"));
562 snap_to_border_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "snap_to_border_check"));
563 snap_to_window_check = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "snap_to_window_check"));
564 double_click_action_combo = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
565 "double_click_action_combo"));
566 snap_width_scale = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "snap_width_scale"));
567 wrap_resistance_scale = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
568 "wrap_resistance_scale"));
569
570 /* Advanced tab: double click action */
571 {
572 gtk_cell_layout_clear (GTK_CELL_LAYOUT (double_click_action_combo));
573
574 renderer = gtk_cell_renderer_text_new ();
575 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (double_click_action_combo), renderer, TRUE);
576 gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (double_click_action_combo), renderer,
577 "text", 0);
578
579 list_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
580 gtk_combo_box_set_model (GTK_COMBO_BOX (double_click_action_combo),
581 GTK_TREE_MODEL (list_store));
582
583 for (template = double_click_values; template->name != NULL; ++template)
584 {
585 gtk_list_store_append (list_store, &iter);
586 gtk_list_store_set (list_store, &iter, 0, _(template->name), 1, template->value, -1);
587 }
588 g_object_unref (G_OBJECT (list_store));
589 xfconf_channel_get_property (settings->priv->wm_channel, "/general/double_click_action",
590 &value);
591 xfwm_settings_double_click_action_property_changed (settings->priv->wm_channel,
592 "/general/double_click_action",
593 &value, settings);
594 g_value_unset (&value);
595
596 g_signal_connect (double_click_action_combo, "changed",
597 G_CALLBACK (xfwm_settings_double_click_action_changed),
598 settings);
599 g_signal_connect (settings->priv->wm_channel, "property-changed::/general/double_click_action",
600 G_CALLBACK (xfwm_settings_double_click_action_property_changed), settings);
601 }
602
603 /* Advanced tab */
604 xfconf_g_property_bind (settings->priv->wm_channel, "/general/snap_width", G_TYPE_INT,
605 range_debouncer_bind (GTK_RANGE (snap_width_scale)), "value");
606 xfconf_g_property_bind (settings->priv->wm_channel, "/general/wrap_resistance", G_TYPE_INT,
607 range_debouncer_bind (GTK_RANGE (wrap_resistance_scale)), "value");
608 xfconf_g_property_bind (settings->priv->wm_channel, "/general/box_move", G_TYPE_BOOLEAN,
609 box_move_check, "active");
610 xfconf_g_property_bind (settings->priv->wm_channel, "/general/box_resize", G_TYPE_BOOLEAN,
611 box_resize_check, "active");
612 xfconf_g_property_bind (settings->priv->wm_channel, "/general/wrap_workspaces", G_TYPE_BOOLEAN,
613 wrap_workspaces_check, "active");
614 xfconf_g_property_bind (settings->priv->wm_channel, "/general/wrap_windows", G_TYPE_BOOLEAN,
615 wrap_windows_check, "active");
616 xfconf_g_property_bind (settings->priv->wm_channel, "/general/snap_to_border", G_TYPE_BOOLEAN,
617 snap_to_border_check, "active");
618 xfconf_g_property_bind (settings->priv->wm_channel, "/general/snap_to_windows", G_TYPE_BOOLEAN,
619 snap_to_window_check, "active");
620
621 /* Load shortcuts */
622 xfwm_settings_initialize_shortcuts (settings);
623 xfwm_settings_reload_shortcuts (settings);
624
625 /* Connect to shortcuts provider */
626 g_signal_connect (settings->priv->provider, "shortcut-added",
627 G_CALLBACK (xfwm_settings_shortcut_added), settings);
628 g_signal_connect (settings->priv->provider, "shortcut-removed",
629 G_CALLBACK (xfwm_settings_shortcut_removed), settings);
630 }
631
632
633
634 static void
xfwm_settings_finalize(GObject * object)635 xfwm_settings_finalize (GObject *object)
636 {
637 XfwmSettings *settings = XFWM_SETTINGS (object);
638
639 g_object_unref (settings->priv->wm_channel);
640 g_object_unref (settings->priv->provider);
641 g_object_unref (settings->priv->builder);
642
643 (*G_OBJECT_CLASS (xfwm_settings_parent_class)->finalize) (object);
644 }
645
646
647
648 static void
xfwm_settings_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)649 xfwm_settings_get_property (GObject *object,
650 guint prop_id,
651 GValue *value,
652 GParamSpec *pspec)
653 {
654 XfwmSettings *settings = XFWM_SETTINGS (object);
655
656 switch (prop_id)
657 {
658 case PROP_GTK_BUILDER:
659 g_value_set_object (value, settings->priv->builder);
660 break;
661 default:
662 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
663 break;
664 }
665 }
666
667
668
669 static void
xfwm_settings_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)670 xfwm_settings_set_property (GObject *object,
671 guint prop_id,
672 const GValue *value,
673 GParamSpec *pspec)
674 {
675 XfwmSettings *settings = XFWM_SETTINGS (object);
676
677 switch (prop_id)
678 {
679 case PROP_GTK_BUILDER:
680 if (GTK_IS_BUILDER (settings->priv->builder))
681 g_object_unref (settings->priv->builder);
682 settings->priv->builder = g_value_get_object (value);
683 g_object_notify (object, "gtk-builder");
684 break;
685 default:
686 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
687 break;
688 }
689 }
690
691
692
693 XfwmSettings *
xfwm_settings_new(void)694 xfwm_settings_new (void)
695 {
696 XfwmSettings *settings = NULL;
697 GtkBuilder *builder;
698
699 builder = gtk_builder_new ();
700
701 gtk_builder_add_from_string (builder, xfwm4_dialog_ui, xfwm4_dialog_ui_length, NULL);
702
703 if (G_LIKELY (builder != NULL))
704 settings = g_object_new (XFWM_TYPE_SETTINGS, "gtk-builder", builder, NULL);
705
706 return settings;
707 }
708
709
710 static gint
xfwm_settings_theme_sort_func(GtkTreeModel * model,GtkTreeIter * iter1,GtkTreeIter * iter2,gpointer data)711 xfwm_settings_theme_sort_func (GtkTreeModel *model,
712 GtkTreeIter *iter1,
713 GtkTreeIter *iter2,
714 gpointer data)
715 {
716 gchar *str1 = NULL;
717 gchar *str2 = NULL;
718
719 gtk_tree_model_get (model, iter1, 0, &str1, -1);
720 gtk_tree_model_get (model, iter2, 0, &str2, -1);
721
722 if (str1 == NULL) str1 = g_strdup ("");
723 if (str2 == NULL) str2 = g_strdup ("");
724
725 if (g_str_equal (str1, DEFAULT_THEME))
726 return -1;
727
728 if (g_str_equal (str2, DEFAULT_THEME))
729 return 1;
730
731 return g_utf8_collate (str1, str2);
732 }
733
734
735
736 static void
xfwm_settings_load_themes(XfwmSettings * settings)737 xfwm_settings_load_themes (XfwmSettings *settings)
738 {
739 GtkTreeModel *model;
740 GtkTreeIter iter;
741 GtkWidget *view;
742 GHashTable *themes;
743 GDir *dir;
744 const gchar *file;
745 gchar **theme_dirs;
746 gchar *filename;
747 gchar *active_theme_name;
748 gint i;
749
750 themes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
751
752 view = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "theme_name_treeview"));
753 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
754
755 xfce_resource_push_path (XFCE_RESOURCE_THEMES, DATADIR G_DIR_SEPARATOR_S "themes");
756 theme_dirs = xfce_resource_dirs (XFCE_RESOURCE_THEMES);
757 xfce_resource_pop_path (XFCE_RESOURCE_THEMES);
758
759 active_theme_name = xfconf_channel_get_string (settings->priv->wm_channel, "/general/theme", DEFAULT_THEME);
760
761 for (i = 0; theme_dirs[i] != NULL; ++i)
762 {
763 dir = g_dir_open (theme_dirs[i], 0, NULL);
764
765 if (G_UNLIKELY (dir == NULL))
766 continue;
767
768 while ((file = g_dir_read_name (dir)) != NULL)
769 {
770 filename = g_build_filename (theme_dirs[i], file, "xfwm4", "themerc", NULL);
771
772 /* check if the theme rc exists and there is not already a theme with the
773 * same name in the database */
774 if (g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR) &&
775 g_hash_table_lookup (themes, file) == NULL)
776 {
777 g_hash_table_insert (themes, g_strdup (file), GINT_TO_POINTER (1));
778
779 /* insert in the list store */
780 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
781 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
782 COL_THEME_NAME, file,
783 COL_THEME_RC, filename, -1);
784
785 if (G_UNLIKELY (g_str_equal (active_theme_name, file)))
786 {
787 GtkTreePath *path = gtk_tree_model_get_path (model, &iter);
788
789 gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)),
790 &iter);
791 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), path, NULL, TRUE, 0.5, 0.5);
792
793 gtk_tree_path_free (path);
794 }
795 }
796
797 g_free (filename);
798 }
799
800 g_dir_close (dir);
801 }
802
803 g_free (active_theme_name);
804 g_strfreev (theme_dirs);
805 g_hash_table_destroy (themes);
806 }
807
808
809
810 static GtkWidget *
xfwm_settings_create_dialog(XfwmSettings * settings)811 xfwm_settings_create_dialog (XfwmSettings *settings)
812 {
813 g_return_val_if_fail (XFWM_IS_SETTINGS (settings), NULL);
814 return GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "main-dialog"));
815 }
816
817
818
819 static GtkWidget *
xfwm_settings_create_plug(XfwmSettings * settings,Window socket_id)820 xfwm_settings_create_plug (XfwmSettings *settings,
821 Window socket_id)
822 {
823 GtkWidget *plug;
824 GtkWidget *child;
825
826 g_return_val_if_fail (XFWM_IS_SETTINGS (settings), NULL);
827
828 plug = gtk_plug_new (socket_id);
829 gtk_widget_show (plug);
830
831 child = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "plug-child"));
832 xfwm_widget_reparent (child, plug);
833 gtk_widget_show (child);
834
835 return plug;
836 }
837
838
839
840 static void
xfwm_settings_response(GtkWidget * dialog,gint response_id)841 xfwm_settings_response (GtkWidget *dialog,
842 gint response_id)
843 {
844 if (response_id == GTK_RESPONSE_HELP)
845 {
846 xfce_dialog_show_help (GTK_WINDOW (dialog), "xfwm4",
847 "preferences", NULL);
848 }
849 else
850 {
851 gtk_main_quit ();
852 }
853 }
854
855
856
857 int
main(int argc,char ** argv)858 main (int argc,
859 char **argv)
860 {
861 XfwmSettings *settings;
862 GtkWidget *dialog;
863 GtkWidget *plug;
864 GError *error = NULL;
865 const gchar *wm_name;
866
867 #ifdef ENABLE_NLS
868 xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
869 #endif
870
871 if (G_UNLIKELY (!gtk_init_with_args (&argc, &argv, _("."), opt_entries, PACKAGE, &error)))
872 {
873 if (G_LIKELY (error != NULL))
874 {
875 g_print (_("%s: %s\nTry %s --help to see a full list of available command line options.\n"),
876 PACKAGE, error->message, PACKAGE_NAME);
877 g_error_free (error);
878 }
879
880 return EXIT_FAILURE;
881 }
882
883 wm_name = gdk_x11_screen_get_window_manager_name (gdk_screen_get_default ());
884 if (G_UNLIKELY (g_ascii_strcasecmp (wm_name, "Xfwm4")))
885 {
886 g_print ("These settings cannot work with your current window manager (%s)\n", wm_name);
887 return EXIT_FAILURE;
888 }
889
890 if (G_UNLIKELY (opt_version))
891 {
892 g_print ("%s\n", PACKAGE_STRING);
893 return EXIT_SUCCESS;
894 }
895
896 if (G_UNLIKELY (!xfconf_init (&error)))
897 {
898 if (G_LIKELY (error != NULL))
899 {
900 g_error (_("Failed to initialize xfconf. Reason: %s"), error->message);
901 g_error_free (error);
902 }
903
904 return EXIT_FAILURE;
905 }
906
907 settings = xfwm_settings_new ();
908
909 if (G_UNLIKELY (settings == NULL))
910 {
911 g_error (_("Could not create the settings dialog."));
912 xfconf_shutdown ();
913 return EXIT_FAILURE;
914 }
915
916 if (G_UNLIKELY (opt_socket_id == 0))
917 {
918 dialog = xfwm_settings_create_dialog (settings);
919 gtk_widget_show (dialog);
920 g_signal_connect (dialog, "response", G_CALLBACK (xfwm_settings_response), NULL);
921
922 /* To prevent the settings dialog to be saved in the session */
923 gdk_x11_set_sm_client_id ("FAKE ID");
924
925 gtk_main ();
926
927 gtk_widget_destroy (dialog);
928 }
929 else
930 {
931 plug = xfwm_settings_create_plug (settings, opt_socket_id);
932 g_signal_connect (plug, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
933
934 /* To prevent the settings dialog to be saved in the session */
935 gdk_x11_set_sm_client_id ("FAKE ID");
936
937 /* Stop startup notification */
938 gdk_notify_startup_complete ();
939
940 gtk_main ();
941 }
942
943 g_object_unref (settings);
944
945 xfconf_shutdown ();
946
947 return EXIT_SUCCESS;
948 }
949
950
951
952 static void
xfwm_settings_theme_selection_changed(GtkTreeSelection * selection,XfwmSettings * settings)953 xfwm_settings_theme_selection_changed (GtkTreeSelection *selection,
954 XfwmSettings *settings)
955 {
956 GtkTreeModel *model;
957 GtkTreeIter iter;
958 gchar *theme, *filename;
959 XfceRc *rc;
960 GtkWidget *widget;
961 gboolean button_layout = FALSE;
962 gboolean title_alignment = FALSE;
963
964 if (gtk_tree_selection_get_selected (selection, &model, &iter))
965 {
966 gtk_tree_model_get (model, &iter,
967 COL_THEME_NAME, &theme,
968 COL_THEME_RC, &filename, -1);
969
970 /* set the theme name */
971 xfconf_channel_set_string (settings->priv->wm_channel, "/general/theme", theme);
972 g_free (theme);
973
974 /* check in the rc if the theme supports a custom button layout and/or
975 * title alignement */
976 rc = xfce_rc_simple_open (filename, TRUE);
977 g_free (filename);
978
979 if (G_LIKELY (rc != NULL))
980 {
981 button_layout = !xfce_rc_has_entry (rc, "button_layout");
982 title_alignment = !xfce_rc_has_entry (rc, "title_alignment");
983 xfce_rc_close (rc);
984 }
985 }
986
987 widget = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "button_layout_box"));
988 gtk_widget_set_sensitive (widget, button_layout);
989
990 widget = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "title_align_box"));
991 gtk_widget_set_sensitive (widget, title_alignment);
992 }
993
994
995
996 static void
xfwm_settings_title_alignment_changed(GtkComboBox * combo,XfwmSettings * settings)997 xfwm_settings_title_alignment_changed (GtkComboBox *combo,
998 XfwmSettings *settings)
999 {
1000 GtkTreeModel *model;
1001 GtkTreeIter iter;
1002 gchar *alignment;
1003
1004 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1005
1006 model = gtk_combo_box_get_model (combo);
1007
1008 gtk_combo_box_get_active_iter (combo, &iter);
1009 gtk_tree_model_get (model, &iter, 1, &alignment, -1);
1010
1011 xfconf_channel_set_string (settings->priv->wm_channel, "/general/title_alignment", alignment);
1012
1013 g_free (alignment);
1014 }
1015
1016
1017
1018 static void
xfwm_settings_active_frame_drag_data(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,GtkSelectionData * data,guint info,guint timestamp,XfwmSettings * settings)1019 xfwm_settings_active_frame_drag_data (GtkWidget *widget,
1020 GdkDragContext *drag_context,
1021 gint x,
1022 gint y,
1023 GtkSelectionData *data,
1024 guint info,
1025 guint timestamp,
1026 XfwmSettings *settings)
1027 {
1028 GtkWidget *source;
1029 GtkWidget *parent;
1030 GtkWidget *active_box;
1031 GList *children;
1032 GList *iter;
1033 GtkAllocation allocation;
1034 gint xoffset;
1035 gint i;
1036
1037 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1038
1039 source = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
1040 (const gchar *)gtk_selection_data_get_data (data)));
1041 parent = gtk_widget_get_parent (source);
1042
1043 active_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "active-box"));
1044
1045 g_object_ref (source);
1046 gtk_container_remove (GTK_CONTAINER (parent), source);
1047 gtk_box_pack_start (GTK_BOX (active_box), source, info == 3, info == 3, 0);
1048 g_object_unref (source);
1049
1050 gtk_widget_get_allocation (widget, &allocation);
1051
1052 xoffset = allocation.x;
1053
1054 children = gtk_container_get_children (GTK_CONTAINER (active_box));
1055
1056 for (i = 0, iter = children; iter != NULL; ++i, iter = g_list_next (iter))
1057 if (gtk_widget_get_visible (GTK_WIDGET (iter->data)))
1058 {
1059 gtk_widget_get_allocation (GTK_WIDGET (iter->data), &allocation);
1060
1061 if (x < allocation.width / 2 + allocation.x - xoffset)
1062 break;
1063 }
1064
1065 g_list_free (children);
1066
1067 gtk_box_reorder_child (GTK_BOX (active_box), source, i);
1068
1069 xfwm_settings_save_button_layout (settings, GTK_CONTAINER (active_box));
1070 gtk_widget_show (source);
1071 }
1072
1073
1074
1075 static gboolean
xfwm_settings_active_frame_drag_motion(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,guint timestamp,XfwmSettings * settings)1076 xfwm_settings_active_frame_drag_motion (GtkWidget *widget,
1077 GdkDragContext *drag_context,
1078 gint x,
1079 gint y,
1080 guint timestamp,
1081 XfwmSettings *settings)
1082 {
1083 GtkWidget *active_box;
1084 GList *children;
1085 GList *iter;
1086 GtkAllocation allocation;
1087 gint xoffset;
1088 gint index = -1;
1089
1090 g_return_val_if_fail (XFWM_IS_SETTINGS (settings), FALSE);
1091
1092 gtk_widget_get_allocation (widget, &allocation);
1093
1094 xoffset = allocation.x;
1095
1096 active_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "active-box"));
1097 children = gtk_container_get_children (GTK_CONTAINER (active_box));
1098
1099 /* Set a value so that the compiler does not (rightfully) complain */
1100 for (iter = children, index = 0; iter != NULL; iter = g_list_next (iter))
1101 {
1102 if (gtk_widget_get_visible (GTK_WIDGET (iter->data)))
1103 {
1104 gtk_widget_get_allocation (GTK_WIDGET (iter->data), &allocation);
1105
1106 if (x < (allocation.width / 2 + allocation.x - xoffset))
1107 break;
1108
1109 index++;
1110 }
1111 }
1112
1113 g_list_free (children);
1114
1115 g_object_set_data (G_OBJECT (widget), "indicator-position", GINT_TO_POINTER (index));
1116 gtk_widget_queue_draw (widget);
1117
1118 return FALSE;
1119 }
1120
1121
1122
1123 static void
xfwm_settings_active_frame_drag_leave(GtkWidget * widget,GdkDragContext * drag_context,guint timestamp,XfwmSettings * settings)1124 xfwm_settings_active_frame_drag_leave (GtkWidget *widget,
1125 GdkDragContext *drag_context,
1126 guint timestamp,
1127 XfwmSettings *settings)
1128 {
1129 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1130
1131 g_object_set_data (G_OBJECT (widget), "indicator-position", GINT_TO_POINTER (-1));
1132 gtk_widget_queue_draw (widget);
1133 }
1134
1135
1136
1137 static void
xfwm_settings_hidden_frame_drag_data(GtkWidget * widget,GdkDragContext * drag_context,gint x,gint y,GtkSelectionData * data,guint info,guint timestamp,XfwmSettings * settings)1138 xfwm_settings_hidden_frame_drag_data (GtkWidget *widget,
1139 GdkDragContext *drag_context,
1140 gint x,
1141 gint y,
1142 GtkSelectionData *data,
1143 guint info,
1144 guint timestamp,
1145 XfwmSettings *settings)
1146 {
1147 GtkWidget *source;
1148 GtkWidget *parent;
1149 GtkWidget *hidden_box;
1150 GtkWidget *active_box;
1151
1152 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1153
1154 source = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
1155 (const gchar *)gtk_selection_data_get_data (data)));
1156 parent = gtk_widget_get_parent (source);
1157
1158 hidden_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "hidden-box"));
1159 active_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "active-box"));
1160
1161 if (G_LIKELY (parent != hidden_box))
1162 {
1163 g_object_ref (source);
1164 gtk_container_remove (GTK_CONTAINER (parent), source);
1165 gtk_box_pack_start (GTK_BOX (hidden_box), source, FALSE, FALSE, 0);
1166 g_object_unref (source);
1167
1168 xfwm_settings_save_button_layout (settings, GTK_CONTAINER (active_box));
1169 }
1170
1171 gtk_widget_show (source);
1172 }
1173
1174
1175
1176 static gboolean
xfwm_settings_title_button_press_event(GtkWidget * widget)1177 xfwm_settings_title_button_press_event (GtkWidget *widget)
1178 {
1179 /* FIXME! This crashes in cairo... xfce bug 14606 */
1180 #if 0
1181 GdkPixbuf *pixbuf;
1182
1183 g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
1184 /* set pixbuf before drag begin cause it can be not displayed */
1185 pixbuf = xfwm_settings_create_icon_from_widget (widget);
1186 gtk_drag_source_set_icon_pixbuf (widget, pixbuf);
1187 g_object_unref (pixbuf);
1188 #endif
1189
1190 return TRUE;
1191 }
1192
1193
1194
1195 static void
xfwm_settings_title_button_drag_data(GtkWidget * widget,GdkDragContext * drag_context,GtkSelectionData * data,guint info,guint timestamp)1196 xfwm_settings_title_button_drag_data (GtkWidget *widget,
1197 GdkDragContext *drag_context,
1198 GtkSelectionData *data,
1199 guint info,
1200 guint timestamp)
1201 {
1202 const gchar *name;
1203
1204 name = gtk_buildable_get_name (GTK_BUILDABLE (widget));
1205
1206 gtk_selection_data_set (data, gdk_atom_intern ("_xfwm4_button_layout", FALSE), 8,
1207 (const guchar *)name, strlen (name));
1208 }
1209
1210
1211
1212 static void
xfwm_settings_title_button_drag_begin(GtkWidget * widget,GdkDragContext * drag_context)1213 xfwm_settings_title_button_drag_begin (GtkWidget *widget,
1214 GdkDragContext *drag_context)
1215 {
1216 g_return_if_fail (GTK_IS_WIDGET (widget));
1217
1218 gtk_widget_hide (widget);
1219 }
1220
1221
1222
1223 static void
xfwm_settings_title_button_drag_end(GtkWidget * widget,GdkDragContext * drag_context)1224 xfwm_settings_title_button_drag_end (GtkWidget *widget,
1225 GdkDragContext *drag_context)
1226 {
1227 gtk_widget_show (widget);
1228 }
1229
1230
1231
1232 static gboolean
xfwm_settings_active_frame_draw(GtkWidget * widget,cairo_t * cr,XfwmSettings * settings)1233 xfwm_settings_active_frame_draw (GtkWidget *widget,
1234 cairo_t *cr,
1235 XfwmSettings *settings)
1236 {
1237 GtkWidget *active_box;
1238 gint position;
1239 GList *children;
1240 GList *iter;
1241 GtkAllocation widget_allocation;
1242 GtkAllocation box_allocation;
1243 gint index;
1244 gint x;
1245 gint spacing;
1246 gint hshift;
1247 GdkRGBA color;
1248
1249 active_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "active-box"));
1250
1251 position = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "indicator-position"));
1252
1253 if (position >= 0)
1254 {
1255 gtk_widget_get_allocation (active_box, &box_allocation);
1256
1257 spacing = gtk_box_get_spacing (GTK_BOX (active_box));
1258 x = box_allocation.x - spacing;
1259
1260 children = gtk_container_get_children (GTK_CONTAINER (active_box));
1261
1262 for (iter = children, index = 1; iter != NULL; iter = g_list_next (iter))
1263 {
1264 if (gtk_widget_get_visible (GTK_WIDGET (iter->data)))
1265 {
1266 if (index == position)
1267 {
1268 gtk_widget_get_allocation (GTK_WIDGET (iter->data), &widget_allocation);
1269 x = widget_allocation.x + widget_allocation.width;
1270 }
1271
1272 index++;
1273 }
1274 }
1275
1276 g_list_free (children);
1277
1278 gtk_widget_get_allocation (widget, &widget_allocation);
1279
1280 gtk_style_context_get_color (gtk_widget_get_style_context (widget),
1281 GTK_STATE_FLAG_NORMAL, &color);
1282
1283 cairo_translate (cr,
1284 box_allocation.x - widget_allocation.x,
1285 box_allocation.y - widget_allocation.y);
1286
1287 hshift = spacing * 5 / 3;
1288 x -= box_allocation.x + (hshift - spacing) / 2;
1289
1290 gdk_cairo_set_source_rgba (cr, &color);
1291 cairo_move_to (cr, x, -spacing);
1292 cairo_rel_line_to (cr, hshift, 0);
1293 cairo_rel_line_to (cr, -(hshift / 2 - 1), spacing);
1294 cairo_rel_line_to (cr, 0, box_allocation.height);
1295 cairo_rel_line_to (cr, hshift / 2 - 1, spacing);
1296 cairo_rel_line_to (cr, -hshift, 0);
1297 cairo_rel_line_to (cr, hshift / 2 - 1, -spacing);
1298 cairo_rel_line_to (cr, 0, -box_allocation.height);
1299 cairo_rel_line_to (cr, -(hshift / 2 - 1), -spacing);
1300 cairo_close_path (cr);
1301 cairo_fill (cr);
1302 }
1303
1304 return FALSE;
1305 }
1306
1307
1308
1309 static gboolean
xfwm_settings_signal_blocker(GtkWidget * widget)1310 xfwm_settings_signal_blocker (GtkWidget *widget)
1311 {
1312 return TRUE;
1313 }
1314
1315
1316 /* FIXME! This crashes in cairo... xfce bug 14606 */
1317 #if 0
1318 static GdkPixbuf *
1319 xfwm_settings_create_icon_from_widget (GtkWidget *widget)
1320 {
1321 GdkWindow *window;
1322 GtkAllocation allocation;
1323
1324 g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
1325
1326 gtk_widget_get_allocation (widget, &allocation);
1327 window = gtk_widget_get_parent_window (widget);
1328 return gdk_pixbuf_get_from_window (window,
1329 allocation.x, allocation.y,
1330 allocation.width, allocation.height);
1331 }
1332 #endif
1333
1334
1335 static void
xfwm_settings_button_layout_property_changed(XfconfChannel * channel,const gchar * property,const GValue * value,XfwmSettings * settings)1336 xfwm_settings_button_layout_property_changed (XfconfChannel *channel,
1337 const gchar *property,
1338 const GValue *value,
1339 XfwmSettings *settings)
1340 {
1341 GtkWidget *active_box;
1342 GtkWidget *hidden_box;
1343 GtkWidget *button;
1344 GList *children;
1345 GList *iter;
1346 const gchar *str_value;
1347 const gchar *key_char;
1348
1349 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1350
1351 hidden_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "hidden-box"));
1352 active_box = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "active-box"));
1353
1354 gtk_widget_set_app_paintable (active_box, FALSE);
1355 gtk_widget_set_app_paintable (hidden_box, FALSE);
1356
1357 children = gtk_container_get_children (GTK_CONTAINER (active_box));
1358
1359 /* Move all buttons to the hidden list, except for the title */
1360 for (iter = children; iter != NULL; iter = g_list_next (iter))
1361 {
1362 button = GTK_WIDGET (iter->data);
1363 key_char = (const gchar *) g_object_get_data (G_OBJECT (button), "key_char");
1364
1365 if (G_LIKELY (key_char[0] != '|'))
1366 {
1367 g_object_ref (button);
1368 gtk_container_remove (GTK_CONTAINER (active_box), button);
1369 gtk_box_pack_start (GTK_BOX (hidden_box), button, FALSE, FALSE, 0);
1370 g_object_unref (button);
1371 }
1372 }
1373
1374 g_list_free (children);
1375
1376 children = g_list_concat (gtk_container_get_children (GTK_CONTAINER (active_box)),
1377 gtk_container_get_children (GTK_CONTAINER (hidden_box)));
1378
1379 /* Move buttons to the active list */
1380 for (str_value = g_value_get_string (value); str_value != NULL && *str_value != '\0'; ++str_value)
1381 for (iter = children; iter != NULL; iter = g_list_next (iter))
1382 {
1383 button = GTK_WIDGET (iter->data);
1384 key_char = (const gchar *) g_object_get_data (G_OBJECT (button), "key_char");
1385
1386 if (g_str_has_prefix (str_value, key_char))
1387 {
1388 g_object_ref (button);
1389 gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (button)), button);
1390 gtk_box_pack_start (GTK_BOX (active_box), button,
1391 key_char[0] == '|', key_char[0] == '|', 0);
1392 g_object_unref (button);
1393 }
1394 }
1395
1396 g_list_free (children);
1397
1398 gtk_widget_set_app_paintable (active_box, TRUE);
1399 gtk_widget_set_app_paintable (hidden_box, TRUE);
1400 }
1401
1402
1403
1404 static void
xfwm_settings_title_alignment_property_changed(XfconfChannel * channel,const gchar * property,const GValue * value,XfwmSettings * settings)1405 xfwm_settings_title_alignment_property_changed (XfconfChannel *channel,
1406 const gchar *property,
1407 const GValue *value,
1408 XfwmSettings *settings)
1409 {
1410 GtkTreeModel *model;
1411 GtkTreeIter iter;
1412 GtkWidget *combo;
1413 gchar *alignment;
1414 const gchar *new_value;
1415
1416 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1417
1418 combo = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "title_align_combo"));
1419 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
1420
1421 if (gtk_tree_model_get_iter_first (model, &iter))
1422 {
1423 do
1424 {
1425 gtk_tree_model_get (model, &iter, 1, &alignment, -1);
1426
1427 if (G_UNLIKELY (G_VALUE_TYPE (value) == G_TYPE_INVALID))
1428 new_value = "center";
1429 else
1430 new_value = g_value_get_string (value);
1431
1432 if (G_UNLIKELY (g_str_equal (alignment, new_value)))
1433 {
1434 g_free (alignment);
1435 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
1436 break;
1437 }
1438
1439 g_free (alignment);
1440 }
1441 while (gtk_tree_model_iter_next (model, &iter));
1442 }
1443 }
1444
1445
1446
1447 static void
xfwm_settings_save_button_layout(XfwmSettings * settings,GtkContainer * container)1448 xfwm_settings_save_button_layout (XfwmSettings *settings,
1449 GtkContainer *container)
1450 {
1451 GList *children;
1452 GList *iter;
1453 const gchar **key_chars;
1454 gchar *value;
1455 gint i;
1456
1457 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1458
1459 children = gtk_container_get_children (container);
1460
1461 key_chars = g_new0 (const char *, g_list_length (children) + 1);
1462
1463 for (i = 0, iter = children; iter != NULL; ++i, iter = g_list_next (iter))
1464 key_chars[i] = (const gchar *) g_object_get_data (G_OBJECT (iter->data), "key_char");
1465
1466 value = g_strjoinv ("", (gchar **) key_chars);
1467
1468 xfconf_channel_set_string (settings->priv->wm_channel, "/general/button_layout", value);
1469
1470 g_list_free (children);
1471 g_free (key_chars);
1472 g_free (value);
1473 }
1474
1475
1476
1477 static void
xfwm_settings_double_click_action_changed(GtkComboBox * combo,XfwmSettings * settings)1478 xfwm_settings_double_click_action_changed (GtkComboBox *combo,
1479 XfwmSettings *settings)
1480 {
1481 GtkTreeModel *model;
1482 GtkTreeIter iter;
1483 gchar *value;
1484
1485 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1486
1487 model = gtk_combo_box_get_model (combo);
1488 gtk_combo_box_get_active_iter (combo, &iter);
1489 gtk_tree_model_get (model, &iter, 1, &value, -1);
1490
1491 xfconf_channel_set_string (settings->priv->wm_channel, "/general/double_click_action", value);
1492
1493 g_free (value);
1494 }
1495
1496
1497
1498 static void
xfwm_settings_title_button_alignment_changed(GtkComboBox * combo,GtkWidget * button)1499 xfwm_settings_title_button_alignment_changed (GtkComboBox *combo,
1500 GtkWidget *button)
1501 {
1502 GtkTreeModel *model;
1503 GtkTreeIter iter;
1504 gchar *value;
1505 float align = 0.5f;
1506 GList *children;
1507 GList *citer;
1508
1509 model = gtk_combo_box_get_model (combo);
1510 if (gtk_combo_box_get_active_iter (combo, &iter))
1511 {
1512 gtk_tree_model_get (model, &iter, 1, &value, -1);
1513
1514 if (g_str_equal (value, "left"))
1515 align = 0.0f;
1516 else if (g_str_equal (value, "right"))
1517 align = 1.0f;
1518
1519 g_free (value);
1520 }
1521
1522 children = gtk_container_get_children (GTK_CONTAINER (button));
1523 for (citer = children; citer != NULL; citer = g_list_next (citer))
1524 {
1525 if (GTK_IS_LABEL (citer->data))
1526 {
1527 gtk_label_set_xalign (GTK_LABEL (citer->data), align);
1528 break;
1529 }
1530 }
1531 g_list_free (children);
1532 }
1533
1534
1535
1536 static void
xfwm_settings_double_click_action_property_changed(XfconfChannel * channel,const gchar * property,const GValue * value,XfwmSettings * settings)1537 xfwm_settings_double_click_action_property_changed (XfconfChannel *channel,
1538 const gchar *property,
1539 const GValue *value,
1540 XfwmSettings *settings)
1541 {
1542 GtkTreeModel *model;
1543 GtkTreeIter iter;
1544 GtkWidget *combo;
1545 const gchar *new_value;
1546 gchar *current_value;
1547
1548 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1549
1550 combo = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "double_click_action_combo"));
1551 model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
1552
1553 if (G_UNLIKELY (G_VALUE_TYPE (value) == G_TYPE_INVALID))
1554 new_value = "maximize";
1555 else
1556 new_value = g_value_get_string (value);
1557
1558 if (G_LIKELY (gtk_tree_model_get_iter_first (model, &iter)))
1559 {
1560 do
1561 {
1562 gtk_tree_model_get (model, &iter, 1, ¤t_value, -1);
1563
1564 if (G_UNLIKELY (g_str_equal (current_value, new_value)))
1565 {
1566 g_free (current_value);
1567 gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
1568 break;
1569 }
1570
1571 g_free (current_value);
1572 }
1573 while (gtk_tree_model_iter_next (model, &iter));
1574 }
1575 }
1576
1577
1578
1579 static void
xfwm_settings_click_to_focus_property_changed(XfconfChannel * channel,const gchar * property,const GValue * value,XfwmSettings * settings)1580 xfwm_settings_click_to_focus_property_changed (XfconfChannel *channel,
1581 const gchar *property,
1582 const GValue *value,
1583 XfwmSettings *settings)
1584 {
1585 GtkWidget *click_to_focus_radio;
1586 GtkWidget *focus_follows_mouse_radio;
1587 GtkWidget *focus_delay_hbox;
1588
1589 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1590 g_return_if_fail (GTK_IS_BUILDER (settings->priv->builder));
1591
1592 click_to_focus_radio = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
1593 "click_to_focus_radio"));
1594 focus_follows_mouse_radio = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
1595 "focus_follows_mouse_radio"));
1596 focus_delay_hbox = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder,
1597 "focus_delay_hbox"));
1598
1599 if (G_UNLIKELY (G_VALUE_TYPE (value) != G_TYPE_BOOLEAN))
1600 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (click_to_focus_radio), TRUE);
1601 else
1602 {
1603 if (g_value_get_boolean (value))
1604 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (click_to_focus_radio), TRUE);
1605 else
1606 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (focus_follows_mouse_radio), TRUE);
1607 }
1608 gtk_widget_set_sensitive (GTK_WIDGET (focus_delay_hbox),
1609 gtk_toggle_button_get_active (
1610 GTK_TOGGLE_BUTTON (focus_follows_mouse_radio)));
1611 }
1612
1613
1614
1615
1616 static void
xfwm_settings_initialize_shortcuts(XfwmSettings * settings)1617 xfwm_settings_initialize_shortcuts (XfwmSettings *settings)
1618 {
1619 GtkTreeModel *model;
1620 GtkTreeIter iter;
1621 GtkWidget *view;
1622 GList *feature_list;
1623
1624 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1625 g_return_if_fail (GTK_IS_BUILDER (settings->priv->builder));
1626
1627 view = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "shortcuts_treeview"));
1628 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1629
1630 gtk_list_store_clear (GTK_LIST_STORE (model));
1631
1632 if ((feature_list = xfce_shortcuts_xfwm4_get_feature_list ()) != NULL)
1633 {
1634 GList *l;
1635
1636 for (l = g_list_first (feature_list); l != NULL; l = g_list_next (l))
1637 {
1638 gtk_list_store_append (GTK_LIST_STORE (model), &iter);
1639 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1640 SHORTCUTS_NAME_COLUMN,
1641 xfce_shortcuts_xfwm4_get_feature_name (l->data),
1642 SHORTCUTS_FEATURE_COLUMN, l->data,
1643 -1);
1644 }
1645
1646 g_list_free (feature_list);
1647 }
1648 }
1649
1650
1651
1652 static void
xfwm_settings_clear_shortcuts_view(XfwmSettings * settings)1653 xfwm_settings_clear_shortcuts_view (XfwmSettings *settings)
1654 {
1655 GtkTreeModel *model;
1656 GtkTreeIter iter;
1657 GtkWidget *view;
1658
1659 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1660 g_return_if_fail (GTK_IS_BUILDER (settings->priv->builder));
1661
1662 view = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "shortcuts_treeview"));
1663 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1664
1665 if (G_LIKELY (gtk_tree_model_get_iter_first (model, &iter)))
1666 {
1667 do
1668 {
1669 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1670 SHORTCUTS_SHORTCUT_COLUMN, NULL, -1);
1671 }
1672 while (gtk_tree_model_iter_next (model, &iter));
1673 }
1674 }
1675
1676
1677
1678 static void
xfwm_settings_reload_shortcut(XfceShortcut * shortcut,GtkTreeModel * model)1679 xfwm_settings_reload_shortcut (XfceShortcut *shortcut,
1680 GtkTreeModel *model)
1681 {
1682 GtkTreeIter iter;
1683 gchar *feature;
1684
1685 g_return_if_fail (GTK_IS_TREE_MODEL (model));
1686 g_return_if_fail (shortcut != NULL);
1687
1688 if (G_LIKELY (gtk_tree_model_get_iter_first (model, &iter)))
1689 {
1690 do
1691 {
1692 gtk_tree_model_get (model, &iter, SHORTCUTS_FEATURE_COLUMN, &feature, -1);
1693
1694 if (G_UNLIKELY (g_str_equal (feature, shortcut->command)))
1695 {
1696 GdkModifierType modifiers;
1697 guint keyval;
1698 gchar *label;
1699
1700 /* Get the shortcut label */
1701 gtk_accelerator_parse (shortcut->shortcut, &keyval, &modifiers);
1702 label = gtk_accelerator_get_label (keyval, modifiers);
1703
1704 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1705 SHORTCUTS_SHORTCUT_COLUMN, shortcut->shortcut,
1706 SHORTCUTS_SHORTCUT_LABEL_COLUMN, label, -1);
1707 g_free (label);
1708 }
1709
1710 g_free (feature);
1711 }
1712 while (gtk_tree_model_iter_next (model, &iter));
1713 }
1714 }
1715
1716
1717
1718 static void
xfwm_settings_reload_shortcuts(XfwmSettings * settings)1719 xfwm_settings_reload_shortcuts (XfwmSettings *settings)
1720 {
1721 GtkTreeModel *model;
1722 GtkWidget *view;
1723 GList *shortcuts;
1724
1725 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1726 g_return_if_fail (GTK_IS_BUILDER (settings->priv->builder));
1727 g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (settings->priv->provider));
1728
1729 view = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "shortcuts_treeview"));
1730 model = gtk_tree_view_get_model (GTK_TREE_VIEW (view));
1731
1732 xfwm_settings_clear_shortcuts_view (settings);
1733
1734 shortcuts = xfce_shortcuts_provider_get_shortcuts (settings->priv->provider);
1735 g_list_foreach (shortcuts, (GFunc) xfwm_settings_reload_shortcut, model);
1736 xfce_shortcuts_free (shortcuts);
1737 }
1738
1739
1740
1741 static void
xfwm_settings_shortcut_added(XfceShortcutsProvider * provider,const gchar * shortcut,XfwmSettings * settings)1742 xfwm_settings_shortcut_added (XfceShortcutsProvider *provider,
1743 const gchar *shortcut,
1744 XfwmSettings *settings)
1745 {
1746 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1747
1748 DBG ("Shortcut added signal: %s", shortcut);
1749
1750 xfwm_settings_reload_shortcuts (settings);
1751 }
1752
1753
1754
1755 static void
xfwm_settings_shortcut_removed(XfceShortcutsProvider * provider,const gchar * shortcut,XfwmSettings * settings)1756 xfwm_settings_shortcut_removed (XfceShortcutsProvider *provider,
1757 const gchar *shortcut,
1758 XfwmSettings *settings)
1759 {
1760 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1761
1762 DBG ("Shortcut removed signal: %s", shortcut);
1763
1764 xfwm_settings_reload_shortcuts (settings);
1765 }
1766
1767
1768
1769 static void
free_row(GtkTreeRowReference * reference,gpointer unused)1770 free_row (GtkTreeRowReference *reference, gpointer unused)
1771 {
1772 gtk_tree_row_reference_free (reference);
1773 }
1774
1775
1776
1777 static void
free_path(GtkTreePath * path,gpointer unused)1778 free_path (GtkTreePath *path, gpointer unused)
1779 {
1780 gtk_tree_path_free (path);
1781 }
1782
1783
1784
1785 static void
xfwm_settings_shortcut_edit_clicked(GtkButton * button,XfwmSettings * settings)1786 xfwm_settings_shortcut_edit_clicked (GtkButton *button,
1787 XfwmSettings *settings)
1788 {
1789 GtkTreeSelection *selection;
1790 GtkTreeModel *model;
1791 GtkTreePath *path;
1792 GtkWidget *view;
1793 GList *rows;
1794 GList *iter;
1795 GList *row_references = NULL;
1796
1797 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1798 g_return_if_fail (GTK_IS_BUILDER (settings->priv->builder));
1799 g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (settings->priv->provider));
1800
1801 view = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "shortcuts_treeview"));
1802 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1803 rows = gtk_tree_selection_get_selected_rows (selection, &model);
1804
1805 for (iter = g_list_first (rows); iter != NULL; iter = g_list_next (iter))
1806 {
1807 row_references = g_list_append (row_references,
1808 gtk_tree_row_reference_new (model, iter->data));
1809 }
1810
1811 for (iter = g_list_first (row_references); iter != NULL; iter = g_list_next (iter))
1812 {
1813 path = gtk_tree_row_reference_get_path (iter->data);
1814
1815 /* Use the row-activated callback to manage the shortcut editing */
1816 xfwm_settings_shortcut_row_activated (GTK_TREE_VIEW (view),
1817 path, NULL,
1818 settings);
1819
1820 gtk_tree_path_free (path);
1821 }
1822
1823 /* Free row reference list */
1824 g_list_foreach (row_references, (GFunc) free_row, NULL);
1825 g_list_free (row_references);
1826
1827 /* Free row list */
1828 g_list_foreach (rows, (GFunc) free_path, NULL);
1829 g_list_free (rows);
1830 }
1831
1832
1833
1834 static void
xfwm_settings_shortcut_clear_clicked(GtkButton * button,XfwmSettings * settings)1835 xfwm_settings_shortcut_clear_clicked (GtkButton *button,
1836 XfwmSettings *settings)
1837 {
1838 GtkTreeSelection *selection;
1839 GtkTreeModel *model;
1840 GtkTreePath *path;
1841 GtkTreeIter tree_iter;
1842 GtkWidget *view;
1843 GList *rows;
1844 GList *iter;
1845 GList *row_references = NULL;
1846 gchar *shortcut;
1847
1848 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1849 g_return_if_fail (GTK_IS_BUILDER (settings->priv->builder));
1850 g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (settings->priv->provider));
1851
1852 view = GTK_WIDGET (gtk_builder_get_object (settings->priv->builder, "shortcuts_treeview"));
1853 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (view));
1854 rows = gtk_tree_selection_get_selected_rows (selection, &model);
1855
1856 for (iter = g_list_first (rows); iter != NULL; iter = g_list_next (iter))
1857 {
1858 row_references = g_list_append (row_references,
1859 gtk_tree_row_reference_new (model, iter->data));
1860 }
1861
1862 for (iter = g_list_first (row_references); iter != NULL; iter = g_list_next (iter))
1863 {
1864 path = gtk_tree_row_reference_get_path (iter->data);
1865
1866 /* Convert tree path to tree iter */
1867 if (G_LIKELY (gtk_tree_model_get_iter (model, &tree_iter, path)))
1868 {
1869 /* Read shortcut */
1870 gtk_tree_model_get (model, &tree_iter, SHORTCUTS_SHORTCUT_COLUMN, &shortcut, -1);
1871
1872 if (G_LIKELY (shortcut != NULL))
1873 {
1874 DBG ("clear shortcut %s", shortcut);
1875
1876 /* Remove keyboard shortcut via xfconf */
1877 xfce_shortcuts_provider_reset_shortcut (settings->priv->provider, shortcut);
1878
1879 gtk_list_store_set (GTK_LIST_STORE (model), &tree_iter,
1880 SHORTCUTS_SHORTCUT_COLUMN, NULL,
1881 SHORTCUTS_SHORTCUT_LABEL_COLUMN, NULL, -1);
1882
1883 /* Free shortcut string */
1884 g_free (shortcut);
1885 }
1886 }
1887
1888 gtk_tree_path_free (path);
1889 }
1890
1891 /* Free row reference list */
1892 g_list_foreach (row_references, (GFunc) free_row, NULL);
1893 g_list_free (row_references);
1894
1895 /* Free row list */
1896 g_list_foreach (rows, (GFunc) free_path, NULL);
1897 g_list_free (rows);
1898 }
1899
1900
1901
1902 static void
xfwm_settings_shortcut_reset_clicked(GtkButton * button,XfwmSettings * settings)1903 xfwm_settings_shortcut_reset_clicked (GtkButton *button,
1904 XfwmSettings *settings)
1905 {
1906 gint confirm;
1907
1908 g_return_if_fail (XFWM_IS_SETTINGS (settings));
1909 g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (settings->priv->provider));
1910
1911 confirm = xfce_dialog_confirm (NULL, "gtk-yes", NULL,
1912 _("This will reset all shortcuts to their default "
1913 "values. Do you really want to do this?"),
1914 _("Reset to Greybirds"));
1915
1916 if (confirm)
1917 xfce_shortcuts_provider_reset_to_defaults (settings->priv->provider);
1918 }
1919
1920
1921
1922 static gboolean
xfwm_settings_update_treeview_on_conflict_replace(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer shortcut_to_erase)1923 xfwm_settings_update_treeview_on_conflict_replace (GtkTreeModel *model,
1924 GtkTreePath *path,
1925 GtkTreeIter *iter,
1926 gpointer shortcut_to_erase)
1927 {
1928 gchar *shortcut;
1929
1930 gtk_tree_model_get (model, iter, SHORTCUTS_SHORTCUT_COLUMN, &shortcut, -1);
1931
1932 if (g_strcmp0 (shortcut_to_erase, shortcut) == 0)
1933 {
1934 /* We found the iter for which we want to erase the shortcut value */
1935 /* Let's do it! */
1936 gtk_list_store_set (GTK_LIST_STORE (model), iter,
1937 SHORTCUTS_SHORTCUT_COLUMN, NULL,
1938 SHORTCUTS_SHORTCUT_LABEL_COLUMN, NULL, -1);
1939
1940 g_free (shortcut);
1941
1942 return TRUE;
1943 }
1944
1945 g_free (shortcut);
1946
1947 return FALSE;
1948 }
1949
1950
1951 static gboolean
xfwm_settings_validate_shortcut(XfceShortcutDialog * dialog,const gchar * shortcut,XfwmSettings * settings)1952 xfwm_settings_validate_shortcut (XfceShortcutDialog *dialog,
1953 const gchar *shortcut,
1954 XfwmSettings *settings)
1955 {
1956 XfceShortcutsProvider *other_provider = NULL;
1957 XfceShortcut *other_shortcut = NULL;
1958 GList *providers;
1959 GList *iter;
1960 gboolean accepted = TRUE;
1961 gint response;
1962
1963 g_return_val_if_fail (XFCE_IS_SHORTCUT_DIALOG (dialog), FALSE);
1964 g_return_val_if_fail (XFWM_IS_SETTINGS (settings), FALSE);
1965 g_return_val_if_fail (shortcut != NULL, FALSE);
1966
1967 /* Ignore empty shortcuts */
1968 if (G_UNLIKELY (g_utf8_strlen (shortcut, -1) == 0))
1969 return FALSE;
1970
1971 /* Ignore raw 'Return' and 'space' since that may have been used to activate the shortcut row */
1972 if (G_UNLIKELY (g_utf8_collate (shortcut, "Return") == 0 ||
1973 g_utf8_collate (shortcut, "space") == 0))
1974 {
1975 return FALSE;
1976 }
1977
1978 providers = xfce_shortcuts_provider_get_providers ();
1979
1980 if (G_UNLIKELY (providers == NULL))
1981 return TRUE;
1982
1983 for (iter = providers; iter != NULL && other_shortcut == NULL; iter = g_list_next (iter))
1984 {
1985 if (G_UNLIKELY (xfce_shortcuts_provider_has_shortcut (iter->data, shortcut)))
1986 {
1987 other_provider = g_object_ref (iter->data);
1988 other_shortcut = xfce_shortcuts_provider_get_shortcut (iter->data, shortcut);
1989 }
1990 }
1991
1992 xfce_shortcuts_provider_free_providers (providers);
1993
1994 if (G_UNLIKELY (other_shortcut != NULL))
1995 {
1996 if (G_LIKELY (!g_str_equal (xfce_shortcut_dialog_get_action (dialog), other_shortcut->command)))
1997 {
1998 response = xfce_shortcut_conflict_dialog (GTK_WINDOW (dialog),
1999 xfce_shortcuts_provider_get_name (settings->priv->provider),
2000 xfce_shortcuts_provider_get_name (other_provider),
2001 shortcut,
2002 xfce_shortcut_dialog_get_action (dialog),
2003 other_shortcut->command,
2004 FALSE);
2005
2006 if (G_UNLIKELY (response == GTK_RESPONSE_ACCEPT))
2007 {
2008 GObject *view;
2009
2010 xfce_shortcuts_provider_reset_shortcut (other_provider, shortcut);
2011
2012 /* We need to update the treeview to erase the shortcut value */
2013 view = gtk_builder_get_object (settings->priv->builder, "shortcuts_treeview");
2014 gtk_tree_model_foreach (gtk_tree_view_get_model (GTK_TREE_VIEW (view)),
2015 xfwm_settings_update_treeview_on_conflict_replace,
2016 (gpointer) shortcut);
2017 }
2018 else
2019 accepted = FALSE;
2020 }
2021
2022 xfce_shortcut_free (other_shortcut);
2023 g_object_unref (other_provider);
2024 }
2025
2026 return accepted;
2027 }
2028
2029
2030
2031 static void
xfwm_settings_shortcut_row_activated(GtkTreeView * tree_view,GtkTreePath * path,GtkTreeViewColumn * column,XfwmSettings * settings)2032 xfwm_settings_shortcut_row_activated (GtkTreeView *tree_view,
2033 GtkTreePath *path,
2034 GtkTreeViewColumn *column,
2035 XfwmSettings *settings)
2036 {
2037 GtkTreeModel *model;
2038 GtkTreeIter iter;
2039 GtkWidget *dialog;
2040 const gchar *new_shortcut;
2041 gchar *shortcut;
2042 gchar *feature;
2043 gchar *name;
2044 gint response;
2045
2046 g_return_if_fail (XFWM_IS_SETTINGS (settings));
2047 g_return_if_fail (XFCE_IS_SHORTCUTS_PROVIDER (settings->priv->provider));
2048
2049 model = gtk_tree_view_get_model (tree_view);
2050
2051 if (G_LIKELY (gtk_tree_model_get_iter (model, &iter, path)))
2052 {
2053 /* Read shortcut from the activated row */
2054 gtk_tree_model_get (model, &iter,
2055 SHORTCUTS_NAME_COLUMN, &name,
2056 SHORTCUTS_FEATURE_COLUMN, &feature,
2057 SHORTCUTS_SHORTCUT_COLUMN, &shortcut, -1);
2058
2059 /* Request a new shortcut from the user */
2060 dialog = xfce_shortcut_dialog_new ("xfwm4", name, feature);
2061 g_signal_connect (dialog, "validate-shortcut",
2062 G_CALLBACK (xfwm_settings_validate_shortcut), settings);
2063 response = xfce_shortcut_dialog_run (XFCE_SHORTCUT_DIALOG (dialog), gtk_widget_get_toplevel (GTK_WIDGET (tree_view)));
2064
2065 if (G_LIKELY (response == GTK_RESPONSE_OK))
2066 {
2067 /* Remove old shortcut from the settings */
2068 if (G_LIKELY (shortcut != NULL))
2069 xfce_shortcuts_provider_reset_shortcut (settings->priv->provider, shortcut);
2070
2071 /* Get new shortcut entered by the user */
2072 new_shortcut = xfce_shortcut_dialog_get_shortcut (XFCE_SHORTCUT_DIALOG (dialog));
2073
2074 /* Save new shortcut */
2075 xfce_shortcuts_provider_set_shortcut (settings->priv->provider, new_shortcut, feature, FALSE);
2076 }
2077 else if (G_UNLIKELY (response == GTK_RESPONSE_REJECT))
2078 {
2079 /* Remove old shortcut from the settings */
2080 if (G_LIKELY (shortcut != NULL))
2081 {
2082 xfce_shortcuts_provider_reset_shortcut (settings->priv->provider, shortcut);
2083 gtk_list_store_set (GTK_LIST_STORE (model), &iter,
2084 SHORTCUTS_SHORTCUT_COLUMN, NULL,
2085 SHORTCUTS_SHORTCUT_LABEL_COLUMN, NULL, -1);
2086 }
2087 }
2088
2089 /* Destroy the shortcut dialog */
2090 gtk_widget_destroy (dialog);
2091
2092 /* Free strings */
2093 g_free (feature);
2094 g_free (name);
2095 g_free (shortcut);
2096 }
2097 }
2098