1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4 * Nemo
5 *
6 * Copyright (C) 2000 Eazel, Inc.
7 *
8 * Nemo is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * Nemo 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 GNU
16 * General Public License for more details.
17 *
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., 51 Franklin Street, Suite 500, MA 02110-1335, USA.
21 *
22 * Authors: Darin Adler <darin@bentspoon.com>
23 */
24
25 #include <config.h>
26 #include "nemo-desktop-window.h"
27 #include "nemo-window-private.h"
28 #include "nemo-actions.h"
29 #include "nemo-desktop-manager.h"
30 #include "nemo-icon-view.h"
31 #include "nemo-desktop-icon-grid-view.h"
32
33 #include <X11/Xatom.h>
34 #include <gdk/gdkx.h>
35 #include <gtk/gtk.h>
36 #include <gio/gio.h>
37 #include <glib/gi18n.h>
38
39 #include <eel/eel-vfs-extensions.h>
40 #include <libnemo-private/nemo-file-utilities.h>
41 #include <libnemo-private/nemo-icon-names.h>
42 #include <libnemo-private/nemo-global-preferences.h>
43 #include <libnemo-private/nemo-desktop-utils.h>
44
45 #define DEBUG_FLAG NEMO_DEBUG_DESKTOP
46 #include <libnemo-private/nemo-debug.h>
47
48 enum {
49 PROP_MONITOR = 1,
50 NUM_PROPERTIES
51 };
52
53 struct NemoDesktopWindowDetails {
54 gint monitor;
55 gboolean loaded;
56 };
57
58 static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
59
60 G_DEFINE_TYPE (NemoDesktopWindow, nemo_desktop_window,
61 NEMO_TYPE_WINDOW);
62
63 static void
nemo_desktop_window_update_directory(NemoDesktopWindow * window)64 nemo_desktop_window_update_directory (NemoDesktopWindow *window)
65 {
66 GFile *location;
67
68 g_assert (NEMO_IS_DESKTOP_WINDOW (window));
69
70 window->details->loaded = FALSE;
71
72 location = g_file_new_for_uri (EEL_DESKTOP_URI);
73
74 nemo_window_go_to (NEMO_WINDOW (window), location);
75 window->details->loaded = TRUE;
76
77 g_object_unref (location);
78 }
79
80 static void
nemo_desktop_window_dispose(GObject * obj)81 nemo_desktop_window_dispose (GObject *obj)
82 {
83 NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (obj);
84
85 g_signal_handlers_disconnect_by_func (nemo_preferences,
86 nemo_desktop_window_update_directory,
87 window);
88
89 G_OBJECT_CLASS (nemo_desktop_window_parent_class)->dispose (obj);
90 }
91
92 static void
nemo_desktop_window_constructed(GObject * obj)93 nemo_desktop_window_constructed (GObject *obj)
94 {
95 GtkActionGroup *action_group;
96 GtkAction *action;
97 AtkObject *accessible;
98 NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (obj);
99 NemoWindow *nwindow = NEMO_WINDOW (obj);
100
101 G_OBJECT_CLASS (nemo_desktop_window_parent_class)->constructed (obj);
102
103 g_object_set_data (G_OBJECT (window), "monitor_number",
104 GINT_TO_POINTER (window->details->monitor));
105
106 gtk_widget_hide (nwindow->details->statusbar);
107 gtk_widget_hide (nwindow->details->menubar);
108
109 action_group = nemo_window_get_main_action_group (nwindow);
110
111 /* Don't allow close action on desktop */
112 action = gtk_action_group_get_action (action_group,
113 NEMO_ACTION_CLOSE);
114 gtk_action_set_sensitive (action, FALSE);
115
116 /* Don't allow new tab on desktop */
117 action = gtk_action_group_get_action (action_group,
118 NEMO_ACTION_NEW_TAB);
119 gtk_action_set_sensitive (action, FALSE);
120
121 /* Set the accessible name so that it doesn't inherit the cryptic desktop URI. */
122 accessible = gtk_widget_get_accessible (GTK_WIDGET (window));
123
124 if (accessible) {
125 atk_object_set_name (accessible, _("Desktop"));
126 }
127
128 nemo_desktop_window_update_geometry (window);
129
130 gtk_window_set_resizable (GTK_WINDOW (window),
131 FALSE);
132 gtk_window_set_decorated (GTK_WINDOW (window),
133 FALSE);
134
135 gtk_widget_show (GTK_WIDGET (window));
136 }
137
138 static void
nemo_desktop_window_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)139 nemo_desktop_window_get_property (GObject *object,
140 guint property_id,
141 GValue *value,
142 GParamSpec *pspec)
143 {
144 NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (object);
145
146 switch (property_id) {
147 case PROP_MONITOR:
148 g_value_set_int (value, window->details->monitor);
149 break;
150 default:
151 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
152 break;
153 }
154 }
155
156 static void
nemo_desktop_window_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)157 nemo_desktop_window_set_property (GObject *object,
158 guint property_id,
159 const GValue *value,
160 GParamSpec *pspec)
161 {
162 NemoDesktopWindow *window = NEMO_DESKTOP_WINDOW (object);
163
164 switch (property_id) {
165 case PROP_MONITOR:
166 window->details->monitor = g_value_get_int (value);
167 break;
168 default:
169 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
170 break;
171 }
172 }
173
174 static void
nemo_desktop_window_init(NemoDesktopWindow * window)175 nemo_desktop_window_init (NemoDesktopWindow *window)
176 {
177 window->details = G_TYPE_INSTANCE_GET_PRIVATE (window, NEMO_TYPE_DESKTOP_WINDOW,
178 NemoDesktopWindowDetails);
179
180 g_object_set_data (G_OBJECT (window), "is_desktop_window",
181 GINT_TO_POINTER (1));
182
183 /* Make it easier for themes authors to style the desktop window separately */
184 gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (window)), "nemo-desktop-window");
185 }
186
187 NemoDesktopWindow *
nemo_desktop_window_new(gint monitor)188 nemo_desktop_window_new (gint monitor)
189 {
190 GApplication *application;
191 NemoDesktopWindow *window;
192
193 application = g_application_get_default ();
194
195 window = g_object_new (NEMO_TYPE_DESKTOP_WINDOW,
196 "application", application,
197 "disable-chrome", TRUE,
198 "monitor", monitor,
199 NULL);
200
201 /* Stop wrong desktop window size in GTK 3.20*/
202 /* We don't want to set a default size, which the parent does, since this */
203 /* will cause the desktop window to open at the wrong size in gtk 3.20 */
204 #if GTK_CHECK_VERSION (3, 19, 0)
205 gtk_window_set_default_size (GTK_WINDOW (window), -1, -1);
206 #endif
207
208 GdkRGBA transparent = {0, 0, 0, 0};
209 gtk_widget_override_background_color (GTK_WIDGET (window), 0, &transparent);
210
211 /* Point window at the desktop folder.
212 * Note that nemo_desktop_window_init is too early to do this.
213 */
214 nemo_desktop_window_update_directory (window);
215
216 return window;
217 }
218
219 static gboolean
nemo_desktop_window_delete_event(GtkWidget * widget,GdkEventAny * event)220 nemo_desktop_window_delete_event (GtkWidget *widget,
221 GdkEventAny *event)
222 {
223 /* Returning true tells GTK+ not to delete the window. */
224 return TRUE;
225 }
226
227 static void
map(GtkWidget * widget)228 map (GtkWidget *widget)
229 {
230 /* Chain up to realize our children */
231 GTK_WIDGET_CLASS (nemo_desktop_window_parent_class)->map (widget);
232 gdk_window_lower (gtk_widget_get_window (widget));
233
234 GdkWindow *window;
235 GdkRGBA transparent = { 0, 0, 0, 0 };
236
237 window = gtk_widget_get_window (widget);
238 gdk_window_set_background_rgba (window, &transparent);
239 }
240
241 static void
unrealize(GtkWidget * widget)242 unrealize (GtkWidget *widget)
243 {
244 GTK_WIDGET_CLASS (nemo_desktop_window_parent_class)->unrealize (widget);
245 }
246
247 static void
set_wmspec_desktop_hint(GdkWindow * window)248 set_wmspec_desktop_hint (GdkWindow *window)
249 {
250 GdkAtom atom;
251
252 atom = gdk_atom_intern ("_NET_WM_WINDOW_TYPE_DESKTOP", FALSE);
253
254 gdk_property_change (window,
255 gdk_atom_intern ("_NET_WM_WINDOW_TYPE", FALSE),
256 gdk_x11_xatom_to_atom (XA_ATOM), 32,
257 GDK_PROP_MODE_REPLACE, (guchar *) &atom, 1);
258 }
259
260 static void
realize(GtkWidget * widget)261 realize (GtkWidget *widget)
262 {
263 GdkVisual *visual;
264
265 /* Make sure we get keyboard events */
266 gtk_widget_set_events (widget, gtk_widget_get_events (widget)
267 | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
268
269 visual = gdk_screen_get_rgba_visual (gtk_widget_get_screen (widget));
270 if (visual) {
271 gtk_widget_set_visual (widget, visual);
272 }
273
274 /* Do the work of realizing. */
275 GTK_WIDGET_CLASS (nemo_desktop_window_parent_class)->realize (widget);
276
277 /* This is the new way to set up the desktop window */
278 set_wmspec_desktop_hint (gtk_widget_get_window (widget));
279 }
280
281 static NemoIconInfo *
real_get_icon(NemoWindow * window,NemoWindowSlot * slot)282 real_get_icon (NemoWindow *window,
283 NemoWindowSlot *slot)
284 {
285 return nemo_icon_info_lookup_from_name (NEMO_ICON_DESKTOP, 48,
286 gtk_widget_get_scale_factor (GTK_WIDGET (window)));
287 }
288
289 static void
real_sync_title(NemoWindow * window,NemoWindowSlot * slot)290 real_sync_title (NemoWindow *window,
291 NemoWindowSlot *slot)
292 {
293 /* hardcode "Desktop" */
294 gtk_window_set_title (GTK_WINDOW (window), _("Desktop"));
295 }
296
297 static void
real_window_close(NemoWindow * window)298 real_window_close (NemoWindow *window)
299 {
300 /* stub, does nothing */
301 return;
302 }
303
304 static void
nemo_desktop_window_class_init(NemoDesktopWindowClass * klass)305 nemo_desktop_window_class_init (NemoDesktopWindowClass *klass)
306 {
307 GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass);
308 NemoWindowClass *nclass = NEMO_WINDOW_CLASS (klass);
309 GObjectClass *oclass = G_OBJECT_CLASS (klass);
310
311 oclass->constructed = nemo_desktop_window_constructed;
312 oclass->dispose = nemo_desktop_window_dispose;
313 oclass->set_property = nemo_desktop_window_set_property;
314 oclass->get_property = nemo_desktop_window_get_property;
315
316 wclass->realize = realize;
317 wclass->unrealize = unrealize;
318 wclass->map = map;
319 wclass->delete_event = nemo_desktop_window_delete_event;
320
321 nclass->sync_title = real_sync_title;
322 nclass->get_icon = real_get_icon;
323 nclass->close = real_window_close;
324
325 properties[PROP_MONITOR] =
326 g_param_spec_int ("monitor",
327 "Monitor number",
328 "The monitor number this window is assigned to",
329 G_MININT, G_MAXINT, 0,
330 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
331
332 g_type_class_add_private (klass, sizeof (NemoDesktopWindowDetails));
333 g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
334 }
335
336 gboolean
nemo_desktop_window_loaded(NemoDesktopWindow * window)337 nemo_desktop_window_loaded (NemoDesktopWindow *window)
338 {
339 return window->details->loaded;
340 }
341
342 gint
nemo_desktop_window_get_monitor(NemoDesktopWindow * window)343 nemo_desktop_window_get_monitor (NemoDesktopWindow *window)
344 {
345 return window->details->monitor;
346 }
347
348 void
nemo_desktop_window_update_geometry(NemoDesktopWindow * window)349 nemo_desktop_window_update_geometry (NemoDesktopWindow *window)
350 {
351 GdkRectangle rect;
352
353 nemo_desktop_manager_get_window_rect_for_monitor (nemo_desktop_manager_get (),
354 window->details->monitor,
355 &rect);
356
357 DEBUG ("NemoDesktopWindow monitor:%d: x:%d, y:%d, w:%d, h:%d",
358 window->details->monitor,
359 rect.x, rect.y,
360 rect.width, rect.height);
361
362 gtk_window_move (GTK_WINDOW (window), rect.x, rect.y);
363 gtk_widget_set_size_request (GTK_WIDGET (window), rect.width, rect.height);
364 }
365
366 gboolean
nemo_desktop_window_get_grid_adjusts(NemoDesktopWindow * window,gint * h_adjust,gint * v_adjust)367 nemo_desktop_window_get_grid_adjusts (NemoDesktopWindow *window,
368 gint *h_adjust,
369 gint *v_adjust)
370 {
371 NemoView *view;
372 NemoWindowSlot *slot;
373 NemoFile *file;
374
375 slot = nemo_window_get_active_slot (NEMO_WINDOW (window));
376 view = nemo_window_slot_get_current_view (slot);
377
378 g_return_val_if_fail (NEMO_IS_VIEW (view), FALSE);
379
380 file = nemo_view_get_directory_as_file (view);
381
382 nemo_icon_view_get_directory_grid_adjusts (NEMO_ICON_VIEW (view),
383 file,
384 h_adjust,
385 v_adjust);
386
387 return TRUE;
388 }
389
390 gboolean
nemo_desktop_window_set_grid_adjusts(NemoDesktopWindow * window,gint h_adjust,gint v_adjust)391 nemo_desktop_window_set_grid_adjusts (NemoDesktopWindow *window,
392 gint h_adjust,
393 gint v_adjust)
394 {
395 NemoView *view;
396 NemoWindowSlot *slot;
397
398 slot = nemo_window_get_active_slot (NEMO_WINDOW (window));
399 view = nemo_window_slot_get_current_view (slot);
400
401 g_return_val_if_fail (NEMO_IS_DESKTOP_ICON_GRID_VIEW (view), FALSE);
402
403 nemo_desktop_icon_grid_view_set_grid_adjusts (NEMO_DESKTOP_ICON_GRID_VIEW (view),
404 h_adjust,
405 v_adjust);
406
407 return TRUE;
408 }
409
410 GtkActionGroup *
nemo_desktop_window_get_action_group(NemoDesktopWindow * window)411 nemo_desktop_window_get_action_group (NemoDesktopWindow *window)
412 {
413 NemoView *view;
414 NemoWindowSlot *slot;
415
416 slot = nemo_window_get_active_slot (NEMO_WINDOW (window));
417 view = nemo_window_slot_get_current_view (slot);
418
419 g_return_val_if_fail (NEMO_IS_DESKTOP_ICON_GRID_VIEW (view), NULL);
420
421 return nemo_desktop_icon_grid_view_get_action_group (NEMO_DESKTOP_ICON_GRID_VIEW (view));
422 }