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 }