1 /* $Id$ */
2 static char const _copyright[] =
3 "Copyright © 2004-2015 DeforaOS Project <contact@defora.org>";
4 /* This file is part of DeforaOS Desktop Panel */
5 static char const _license[] =
6 "This program is free software: you can redistribute it and/or modify\n"
7 "it under the terms of the GNU General Public License as published by\n"
8 "the Free Software Foundation, version 3 of the License.\n"
9 "\n"
10 "This program is distributed in the hope that it will be useful,\n"
11 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
12 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
13 "GNU General Public License for more details.\n"
14 "\n"
15 "You should have received a copy of the GNU General Public License\n"
16 "along with this program.  If not, see <http://www.gnu.org/licenses/>.";
17 
18 
19 
20 #ifdef __NetBSD__
21 # include <sys/param.h>
22 # include <sys/sysctl.h>
23 #else
24 # include <fcntl.h>
25 #endif
26 #include <unistd.h>
27 #ifdef DEBUG
28 # include <stdio.h>
29 #endif
30 #include <gtk/gtk.h>
31 #include <System.h>
32 #include <Desktop.h>
33 #include <Desktop/Browser.h>
34 
35 
36 /* helper */
37 /* private */
38 /* prototypes */
39 static char const * _panel_helper_config_get(Panel * panel,
40 		char const * section, char const * variable);
41 static int _panel_helper_config_set(Panel * panel, char const * section,
42 		char const * variable, char const * value);
43 static int _panel_helper_error(Panel * panel, char const * message, int ret);
44 static void _panel_helper_about_dialog(Panel * panel);
45 static int _panel_helper_lock(Panel * panel);
46 static void _panel_helper_logout_dialog(Panel * panel);
47 #ifndef HELPER_POSITION_MENU_WIDGET
48 static void _panel_helper_position_menu(Panel * panel, GtkMenu * menu, gint * x,
49 		gint * y, gboolean * push_in, PanelPosition position);
50 static void _panel_helper_position_menu_bottom(Panel * panel, GtkMenu * menu,
51 		gint * x, gint * y, gboolean * push_in);
52 static void _panel_helper_position_menu_top(Panel * panel, GtkMenu * menu,
53 		gint * x, gint * y, gboolean * push_in);
54 #else
55 static void _panel_helper_position_menu_widget(Panel * panel, GtkMenu * menu,
56 		gint * x, gint * y, gboolean * push_in);
57 #endif
58 static void _panel_helper_preferences_dialog(Panel * panel);
59 static void _panel_helper_rotate_screen(Panel * panel);
60 static void _panel_helper_shutdown_dialog(Panel * panel);
61 static int _panel_helper_suspend(Panel * panel);
62 
63 
64 /* functions */
65 /* panel_helper_config_get */
_panel_helper_config_get(Panel * panel,char const * section,char const * variable)66 static char const * _panel_helper_config_get(Panel * panel,
67 		char const * section, char const * variable)
68 {
69 	char const * ret;
70 	String * s = NULL;
71 
72 #ifdef DEBUG
73 	fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\")\n", __func__, section,
74 			variable);
75 #endif
76 	if(section != NULL)
77 	{
78 		if((s = string_new_append("applet::", section, NULL)) == NULL)
79 			return NULL;
80 		section = s;
81 	}
82 	ret = panel_get_config(panel, section, variable);
83 	string_delete(s);
84 	return ret;
85 }
86 
87 
88 /* panel_helper_config_set */
_panel_helper_config_set(Panel * panel,char const * section,char const * variable,char const * value)89 static int _panel_helper_config_set(Panel * panel, char const * section,
90 		char const * variable, char const * value)
91 {
92 	int ret;
93 	String * s = NULL;
94 
95 #ifdef DEBUG
96 	fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\", \"%s\")\n", __func__,
97 			section, variable, value);
98 #endif
99 	if(section != NULL)
100 	{
101 		if((s = string_new_append("applet::", section, NULL)) == NULL)
102 			return -1;
103 		section = s;
104 	}
105 	/* FIXME save the configuration (if not in test mode) */
106 	ret = config_set(panel->config, section, variable, value);
107 	string_delete(s);
108 	return ret;
109 }
110 
111 
112 /* panel_helper_error */
_panel_helper_error(Panel * panel,char const * message,int ret)113 static int _panel_helper_error(Panel * panel, char const * message, int ret)
114 {
115 	return panel_error(panel, message, ret);
116 }
117 
118 
119 /* panel_helper_about_dialog */
120 static gboolean _about_on_closex(gpointer data);
121 
_panel_helper_about_dialog(Panel * panel)122 static void _panel_helper_about_dialog(Panel * panel)
123 {
124 	char const * p;
125 	char const ** q;
126 	char const * authors[] = { NULL, NULL };
127 
128 	if(panel->ab_window != NULL)
129 	{
130 		gtk_window_present(GTK_WINDOW(panel->ab_window));
131 		return;
132 	}
133 	panel->ab_window = desktop_about_dialog_new();
134 	if((authors[0] = panel_get_config(panel, "about", "authors")) != NULL)
135 		q = authors;
136 	else
137 		q = _authors;
138 	desktop_about_dialog_set_authors(panel->ab_window, q);
139 	if((p = panel_get_config(panel, "about", "comment")) == NULL)
140 		p = _("Panel for the DeforaOS desktop");
141 	desktop_about_dialog_set_comments(panel->ab_window, p);
142 	if((p = panel_get_config(panel, "about", "copyright")) == NULL)
143 		p = _copyright;
144 	desktop_about_dialog_set_copyright(panel->ab_window, p);
145 	if((p = panel_get_config(panel, "about", "icon")) == NULL)
146 		p = "panel-settings"; /* XXX */
147 	desktop_about_dialog_set_logo_icon_name(panel->ab_window, p);
148 	if((p = panel_get_config(panel, "about", "license")) == NULL)
149 		p = _license;
150 	desktop_about_dialog_set_license(panel->ab_window, p);
151 	if((p = panel_get_config(panel, "about", "name")) == NULL)
152 		p = PACKAGE;
153 	desktop_about_dialog_set_program_name(panel->ab_window, p);
154 	if((p = panel_get_config(panel, "about", "translator")) == NULL)
155 		p = _("translator-credits");
156 	desktop_about_dialog_set_translator_credits(panel->ab_window, p);
157 	if((p = panel_get_config(panel, "about", "version")) == NULL)
158 		p = VERSION;
159 	desktop_about_dialog_set_version(panel->ab_window, p);
160 	if((p = panel_get_config(panel, "about", "website")) == NULL)
161 		p = "http://www.defora.org/";
162 	desktop_about_dialog_set_website(panel->ab_window, p);
163 	gtk_window_set_position(GTK_WINDOW(panel->ab_window),
164 			GTK_WIN_POS_CENTER);
165 	g_signal_connect_swapped(panel->ab_window, "delete-event", G_CALLBACK(
166 				_about_on_closex), panel);
167 	gtk_widget_show(panel->ab_window);
168 }
169 
_about_on_closex(gpointer data)170 static gboolean _about_on_closex(gpointer data)
171 {
172 	Panel * panel = data;
173 
174 	gtk_widget_hide(panel->ab_window);
175 	return TRUE;
176 }
177 
178 
179 /* panel_helper_lock */
180 static gboolean _lock_on_idle(gpointer data);
181 
_panel_helper_lock(Panel * panel)182 static int _panel_helper_lock(Panel * panel)
183 {
184 	panel->source = g_idle_add(_lock_on_idle, panel);
185 	return 0;
186 }
187 
_lock_on_idle(gpointer data)188 static gboolean _lock_on_idle(gpointer data)
189 {
190 	/* FIXME default to calling XActivateScreenSaver() */
191 	Panel * panel = data;
192 	char const * command = "xset s activate";
193 	char const * p;
194 	GError * error = NULL;
195 
196 	panel->source = 0;
197 	if((p = config_get(panel->config, "lock", "command")) != NULL)
198 		command = p;
199 	if(g_spawn_command_line_async(command, &error) != TRUE)
200 	{
201 		_panel_helper_error(panel, error->message, 1);
202 		g_error_free(error);
203 	}
204 	return FALSE;
205 }
206 
207 
208 /* panel_helper_logout_dialog */
209 static gboolean _logout_dialog_on_closex(gpointer data);
210 static void _logout_dialog_on_response(GtkWidget * widget, gint response);
211 
_panel_helper_logout_dialog(Panel * panel)212 static void _panel_helper_logout_dialog(Panel * panel)
213 {
214 	const char * message = _("This will log you out of the current session,"
215 			" therefore closing any application currently opened"
216 			" and losing any unsaved data.\n"
217 			"Do you really want to proceed?");
218 	GtkWidget * widget;
219 
220 	if(panel->lo_window != NULL)
221 	{
222 		gtk_window_present(GTK_WINDOW(panel->lo_window));
223 		return;
224 	}
225 	panel->lo_window = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_QUESTION,
226 			GTK_BUTTONS_NONE,
227 #if GTK_CHECK_VERSION(2, 6, 0)
228 			"%s", _("Logout"));
229 	gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(
230 				panel->lo_window),
231 #endif
232 			"%s", message);
233 #if GTK_CHECK_VERSION(2, 10, 0)
234 	gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(panel->lo_window),
235 			gtk_image_new_from_icon_name("gnome-logout",
236 				GTK_ICON_SIZE_DIALOG));
237 #endif
238 	gtk_dialog_add_buttons(GTK_DIALOG(panel->lo_window), GTK_STOCK_CANCEL,
239 			GTK_RESPONSE_CANCEL, NULL);
240 	widget = gtk_button_new_with_label(_("Logout"));
241 	gtk_button_set_image(GTK_BUTTON(widget), gtk_image_new_from_icon_name(
242 				"gnome-logout", GTK_ICON_SIZE_BUTTON));
243 	gtk_widget_show_all(widget);
244 	gtk_dialog_add_action_widget(GTK_DIALOG(panel->lo_window), widget,
245 			GTK_RESPONSE_ACCEPT);
246 	gtk_window_set_keep_above(GTK_WINDOW(panel->lo_window), TRUE);
247 	gtk_window_set_position(GTK_WINDOW(panel->lo_window),
248 			GTK_WIN_POS_CENTER);
249 	gtk_window_set_title(GTK_WINDOW(panel->lo_window), _("Logout"));
250 	g_signal_connect_swapped(panel->lo_window, "delete-event", G_CALLBACK(
251 				_logout_dialog_on_closex), panel);
252 	g_signal_connect(panel->lo_window, "response", G_CALLBACK(
253 				_logout_dialog_on_response), panel);
254 	gtk_widget_show_all(panel->lo_window);
255 }
256 
_logout_dialog_on_closex(gpointer data)257 static gboolean _logout_dialog_on_closex(gpointer data)
258 {
259 	Panel * panel = data;
260 
261 	gtk_widget_hide(panel->lo_window);
262 	return TRUE;
263 }
264 
_logout_dialog_on_response(GtkWidget * widget,gint response)265 static void _logout_dialog_on_response(GtkWidget * widget, gint response)
266 {
267 	gtk_widget_hide(widget);
268 	if(response == GTK_RESPONSE_ACCEPT)
269 	{
270 		gtk_main_quit();
271 #ifndef DEBUG
272 		/* XXX assumes the parent process is the session manager */
273 		kill(getppid(), SIGHUP);
274 #endif
275 	}
276 }
277 
278 
279 #ifndef HELPER_POSITION_MENU_WIDGET
280 /* panel_helper_position_menu */
_panel_helper_position_menu(Panel * panel,GtkMenu * menu,gint * x,gint * y,gboolean * push_in,PanelPosition position)281 static void _panel_helper_position_menu(Panel * panel, GtkMenu * menu, gint * x,
282 		gint * y, gboolean * push_in, PanelPosition position)
283 {
284 	GtkRequisition req;
285 	PanelWindow * window = panel->windows[position];
286 
287 	if(window == NULL)
288 		return;
289 #if GTK_CHECK_VERSION(3, 0, 0)
290 	gtk_widget_get_preferred_size(GTK_WIDGET(menu), NULL, &req);
291 #else
292 	gtk_widget_size_request(GTK_WIDGET(menu), &req);
293 #endif
294 #ifdef DEBUG
295 	fprintf(stderr, "DEBUG: %s() width=%d, height=%d\n", __func__,
296 			req.width, req.height);
297 #endif
298 	if(req.height <= 0)
299 		return;
300 	switch(position)
301 	{
302 		case PANEL_POSITION_TOP:
303 			*y = panel_window_get_height(window);
304 			break;
305 		case PANEL_POSITION_BOTTOM:
306 			*y = panel->root_height
307 				- panel_window_get_height(window) - req.height;
308 			break;
309 		case PANEL_POSITION_LEFT:
310 			*x = panel_window_get_width(window);
311 			break;
312 		case PANEL_POSITION_RIGHT:
313 			*x = panel->root_width
314 				- panel_window_get_width(window) - req.width;
315 			break;
316 	}
317 	*push_in = TRUE;
318 }
319 
320 
321 /* panel_helper_position_menu_bottom */
_panel_helper_position_menu_bottom(Panel * panel,GtkMenu * menu,gint * x,gint * y,gboolean * push_in)322 static void _panel_helper_position_menu_bottom(Panel * panel, GtkMenu * menu,
323 		gint * x, gint * y, gboolean * push_in)
324 {
325 	_panel_helper_position_menu(panel, menu, x, y, push_in,
326 			PANEL_POSITION_BOTTOM);
327 }
328 
329 
330 /* panel_helper_position_menu_top */
_panel_helper_position_menu_top(Panel * panel,GtkMenu * menu,gint * x,gint * y,gboolean * push_in)331 static void _panel_helper_position_menu_top(Panel * panel, GtkMenu * menu,
332 		gint * x, gint * y, gboolean * push_in)
333 {
334 	_panel_helper_position_menu(panel, menu, x, y, push_in,
335 			PANEL_POSITION_TOP);
336 }
337 #else
338 /* panel_helper_position_menu_widget */
_panel_helper_position_menu_widget(Panel * panel,GtkMenu * menu,gint * x,gint * y,gboolean * push_in)339 static void _panel_helper_position_menu_widget(Panel * panel, GtkMenu * menu,
340 		gint * x, gint * y, gboolean * push_in)
341 {
342 	GtkRequisition req;
343 	gint sx = 0;
344 	gint sy = 0;
345 
346 #if GTK_CHECK_VERSION(3, 0, 0)
347 	gtk_widget_get_preferred_size(GTK_WIDGET(menu), NULL, &req);
348 #else
349 	gtk_widget_size_request(GTK_WIDGET(menu), &req);
350 #endif
351 #ifdef DEBUG
352 	fprintf(stderr, "DEBUG: %s() width=%d, height=%d\n", __func__,
353 			req.width, req.height);
354 #endif
355 	if(req.height <= 0)
356 		return;
357 	panel_window_get_position(panel->windows[PANEL_POSITION_TOP], x, y);
358 	panel_window_get_size(panel->windows[PANEL_POSITION_TOP], &sx, &sy);
359 	*y += sy;
360 	*push_in = TRUE;
361 }
362 #endif
363 
364 
365 /* panel_helper_preferences_dialog */
_panel_helper_preferences_dialog(Panel * panel)366 static void _panel_helper_preferences_dialog(Panel * panel)
367 {
368 	panel_show_preferences(panel, TRUE);
369 }
370 
371 
372 /* panel_helper_rotate_screen */
_panel_helper_rotate_screen(Panel * panel)373 static void _panel_helper_rotate_screen(Panel * panel)
374 {
375 	desktop_message_send(DESKTOP_CLIENT_MESSAGE, DESKTOP_MESSAGE_SET_LAYOUT,
376 			DESKTOP_LAYOUT_TOGGLE, 0);
377 }
378 
379 
380 /* panel_helper_shutdown_dialog */
381 static gboolean _shutdown_dialog_on_closex(gpointer data);
382 static void _shutdown_dialog_on_response(GtkWidget * widget, gint response,
383 		gpointer data);
384 enum { RES_CANCEL, RES_REBOOT, RES_SHUTDOWN };
385 
_panel_helper_shutdown_dialog(Panel * panel)386 static void _panel_helper_shutdown_dialog(Panel * panel)
387 {
388 #ifdef EMBEDDED
389 	const char * message = _("This will shutdown your device,"
390 			" therefore closing any application currently opened"
391 			" and losing any unsaved data.\n"
392 			"Do you really want to proceed?");
393 #else
394 	const char * message = _("This will shutdown your computer,"
395 			" therefore closing any application currently opened"
396 			" and losing any unsaved data.\n"
397 			"Do you really want to proceed?");
398 #endif
399 	GtkWidget * widget;
400 
401 	if(panel->sh_window != NULL)
402 	{
403 		gtk_window_present(GTK_WINDOW(panel->sh_window));
404 		return;
405 	}
406 	panel->sh_window = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_QUESTION,
407 			GTK_BUTTONS_NONE, "%s",
408 #if GTK_CHECK_VERSION(2, 6, 0)
409 			_("Shutdown"));
410 	gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(
411 				panel->sh_window),
412 #endif
413 			"%s", message);
414 #if GTK_CHECK_VERSION(2, 10, 0)
415 	gtk_message_dialog_set_image(GTK_MESSAGE_DIALOG(panel->sh_window),
416 			gtk_image_new_from_icon_name("gnome-shutdown",
417 				GTK_ICON_SIZE_DIALOG));
418 #endif
419 	gtk_dialog_add_buttons(GTK_DIALOG(panel->sh_window), GTK_STOCK_CANCEL,
420 			RES_CANCEL, _("Restart"), RES_REBOOT, NULL);
421 	widget = gtk_button_new_with_label(_("Shutdown"));
422 	gtk_button_set_image(GTK_BUTTON(widget), gtk_image_new_from_icon_name(
423 				"gnome-shutdown", GTK_ICON_SIZE_BUTTON));
424 	gtk_widget_show_all(widget);
425 	gtk_dialog_add_action_widget(GTK_DIALOG(panel->sh_window), widget,
426 			RES_SHUTDOWN);
427 	gtk_window_set_keep_above(GTK_WINDOW(panel->sh_window), TRUE);
428 	gtk_window_set_position(GTK_WINDOW(panel->sh_window),
429 			GTK_WIN_POS_CENTER);
430 	gtk_window_set_title(GTK_WINDOW(panel->sh_window), _("Shutdown"));
431 	g_signal_connect(panel->sh_window, "delete-event", G_CALLBACK(
432 				_shutdown_dialog_on_closex), panel);
433 	g_signal_connect(panel->sh_window, "response", G_CALLBACK(
434 				_shutdown_dialog_on_response), panel);
435 	gtk_widget_show_all(panel->sh_window);
436 }
437 
_shutdown_dialog_on_closex(gpointer data)438 static gboolean _shutdown_dialog_on_closex(gpointer data)
439 {
440 	Panel * panel = data;
441 
442 	gtk_widget_hide(panel->sh_window);
443 	return TRUE;
444 }
445 
_shutdown_dialog_on_response(GtkWidget * widget,gint response,gpointer data)446 static void _shutdown_dialog_on_response(GtkWidget * widget, gint response,
447 		gpointer data)
448 {
449 	Panel * panel = data;
450 	char * reboot[] = { "/sbin/shutdown", "shutdown", "-r", "now", NULL };
451 	char * shutdown[] = { "/sbin/shutdown", "shutdown",
452 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
453 		"-p",
454 #else
455 		"-h",
456 #endif
457 		"now", NULL };
458 	char ** argv;
459 	GError * error = NULL;
460 
461 	gtk_widget_hide(widget);
462 	if(response == RES_SHUTDOWN)
463 		argv = shutdown;
464 	else if(response == RES_REBOOT)
465 		argv = reboot;
466 	else
467 		return;
468 	if(g_spawn_async(NULL, argv, NULL, G_SPAWN_FILE_AND_ARGV_ZERO, NULL,
469 				NULL, NULL, &error) != TRUE)
470 	{
471 		_panel_helper_error(panel, error->message, 1);
472 		g_error_free(error);
473 	}
474 }
475 
476 
477 /* panel_helper_suspend */
_panel_helper_suspend(Panel * panel)478 static int _panel_helper_suspend(Panel * panel)
479 {
480 #ifdef __NetBSD__
481 	int sleep_state = 3;
482 #else
483 	int fd;
484 	char * suspend[] = { "/usr/bin/sudo", "sudo", "/usr/bin/apm", "-s",
485 		NULL };
486 	const unsigned int flags = G_SPAWN_FILE_AND_ARGV_ZERO;
487 	GError * error = NULL;
488 #endif
489 
490 #ifdef __NetBSD__
491 	if(sysctlbyname("machdep.sleep_state", NULL, NULL, &sleep_state,
492 				sizeof(sleep_state)) != 0)
493 		return -_panel_helper_error(panel, "sysctl", 1);
494 #else
495 	if((fd = open("/sys/power/state", O_WRONLY)) >= 0)
496 	{
497 		write(fd, "mem\n", 4);
498 		close(fd);
499 	}
500 	else if(g_spawn_async(NULL, suspend, NULL, flags, NULL, NULL, NULL,
501 				&error) != TRUE)
502 	{
503 		_panel_helper_error(panel, error->message, 1);
504 		g_error_free(error);
505 		return -1;
506 	}
507 #endif
508 	_panel_helper_lock(panel); /* XXX may already be suspended */
509 	return 0;
510 }
511