launcher.c 26.5 KB
Newer Older
1 2
/*
 * GNOME panel launcher module.
3 4
 * (C) 1997,1998,1999,2000 The Free Software Foundation
 * (C) 2000 Eazel, Inc.
5 6 7
 *
 * Authors: Miguel de Icaza
 *          Federico Mena
8
 * CORBAized by George Lebl
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
9
 * de-CORBAized by George Lebl
10
 *
11 12 13 14
 */

#include <config.h>
#include <stdio.h>
15
#include <sys/types.h>
16 17 18 19
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
Mark McLoughlin's avatar
Mark McLoughlin committed
20 21

#include <libgnome/libgnome.h>
22
#include <libgnome/gnome-desktop-item.h>
Mark McLoughlin's avatar
Mark McLoughlin committed
23
#include <libgnomeui/libgnomeui.h>
24
#include <libgnomeui/gnome-ditem-edit.h>
25
#include <libgnomevfs/gnome-vfs.h>
26
#include <gdk/gdkx.h>
27

Mark McLoughlin's avatar
Mark McLoughlin committed
28 29 30 31 32 33
#include "launcher.h"

#include "button-widget.h"
#include "menu-fentry.h"
#include "menu.h"
#include "panel-util.h"
34
#include "panel-config-global.h"
35
#include "panel-gconf.h"
36
#include "panel-profile.h"
Mark McLoughlin's avatar
Mark McLoughlin committed
37
#include "xstuff.h"
38 39 40
#include "panel-toplevel.h"
#include "panel-a11y.h"
#include "panel-globals.h"
Mark McLoughlin's avatar
Mark McLoughlin committed
41

42
#include "quick-desktop-reader.h"
43

44
#include "egg-screen-exec.h"
45
#include "egg-screen-url.h"
46

47
#undef LAUNCHER_DEBUG
48

49
static void properties_apply (Launcher *launcher);
50
static void launcher_save    (Launcher *launcher);
51

52
enum {
53
	REVERT_BUTTON
54 55
};

56 57 58
static GdkScreen *
launcher_get_screen (Launcher *launcher)
{
59
	PanelWidget *panel_widget;
60 61 62 63 64

	g_return_val_if_fail (launcher != NULL, 0);
	g_return_val_if_fail (launcher->info != NULL, 0);
	g_return_val_if_fail (launcher->info->widget != NULL, 0);

65 66 67 68 69
	panel_widget = PANEL_WIDGET (launcher->info->widget->parent);

	return gtk_window_get_screen (GTK_WINDOW (panel_widget->toplevel));
}

70 71 72 73 74 75 76 77 78 79 80 81
static const char *
panel_launcher_get_filename (const char *path)
{
	char *p;

	if ((p = strstr (path, PANEL_LAUNCHERS_PATH)))
		p += sizeof (PANEL_LAUNCHERS_PATH);

	return p;
}

static void
82 83 84 85 86 87
panel_launcher_save_ditem (GnomeDesktopItem *ditem,
			   GdkScreen        *screen)
{
	GError     *error = NULL;
	const char  *location;

88
	g_return_if_fail (ditem != NULL);
89 90 91

	location = gnome_desktop_item_get_location (ditem);
	if (!location) {
92
		char *path;
93

94
		path = panel_make_unique_path (NULL, ".desktop");
95 96
		gnome_desktop_item_set_location (ditem, path);
		g_free (path);
97 98 99 100 101 102 103 104 105 106 107 108
	}

	gnome_desktop_item_save (ditem, NULL, TRUE, &error);
	if (error) {
		panel_error_dialog (
			screen,
			"cannot_save_launcher",
			_("Cannot save launcher to disk, "
			  "the following error occured:\n\n%s"),
			error->message);
		g_error_free (error);
	}
109 110
}

111
static void
112
launch_url (Launcher *launcher)
113
{
114
	GnomeDesktopItem *item;
115 116
	const char *url;
	GError *error = NULL;
117
	GdkScreen *screen;
118

119 120
	g_return_if_fail (launcher != NULL);
	g_return_if_fail (launcher->ditem != NULL);
121

122
	item = launcher->ditem;
123 124 125
	url = gnome_desktop_item_get_string (item,
					     GNOME_DESKTOP_ITEM_URL);

126 127
	screen = launcher_get_screen (launcher);

128 129
	if (!url) {
		panel_error_dialog (
130
			screen,
131 132
			"no_url_dialog",
			_("This launch icon does not specify a url to show"));
133
		return;
134
	}
135

Mark McLoughlin's avatar
Mark McLoughlin committed
136
	egg_url_show_on_screen (url, screen, &error);
137 138
	if (error) {
		panel_error_dialog (
139
			screen,
140 141 142
			"cant_show_url_dialog",
			_("Cannot show %s\n%s"),
			url, error->message);
143
		g_clear_error (&error);
144 145
	}
}
146

147
static void
Mark McLoughlin's avatar
Mark McLoughlin committed
148 149
launch_cb (GtkWidget *widget,
	   Launcher  *launcher)
150 151
{
	GnomeDesktopItem *item;
152

Mark McLoughlin's avatar
Mark McLoughlin committed
153 154
	g_return_if_fail (launcher != NULL);
	g_return_if_fail (launcher->ditem != NULL);
155 156

	item = launcher->ditem;
157

158
	if (panel_global_config_get_enable_animations ())
159 160
		xstuff_zoom_animate (widget, NULL);
	
Mark McLoughlin's avatar
Mark McLoughlin committed
161
	if (gnome_desktop_item_get_entry_type (item) == GNOME_DESKTOP_ITEM_TYPE_LINK)
162
		launch_url (launcher);
Mark McLoughlin's avatar
Mark McLoughlin committed
163 164

	else {
165
		GError *error = NULL;
Mark McLoughlin's avatar
Mark McLoughlin committed
166

167 168
		panel_ditem_launch (
			item, NULL, 0, launcher_get_screen (launcher), &error);
Mark McLoughlin's avatar
Mark McLoughlin committed
169
		if (error) {
170 171 172 173 174
			panel_error_dialog (
				launcher_get_screen (launcher),
				"cannot_launch_icon",
				_("<b>Cannot launch icon</b>\n\n"
				"Details: %s"), error->message);
175
			g_clear_error (&error);
176
		}
177
	}
178
	
179 180 181 182 183 184 185
	if (panel_global_config_get_drawer_auto_close ()) {
		PanelToplevel *toplevel;

		toplevel = PANEL_WIDGET (launcher->button->parent)->toplevel;

		if (panel_toplevel_get_is_attached (toplevel)) 
			panel_toplevel_hide (toplevel, FALSE, -1);
186
	}
187 188
}

189 190 191 192 193 194 195 196 197 198
static void
drag_data_received_cb (GtkWidget        *widget,
		       GdkDragContext   *context,
		       gint              x,
		       gint              y,
		       GtkSelectionData *selection_data,
		       guint             info,
		       guint             time,
		       Launcher         *launcher)
{
199
	GError *error = NULL;
200 201 202 203 204 205 206 207 208 209 210 211 212
	char **envp = NULL;

	GdkScreen *screen = launcher_get_screen (launcher);

	if (gdk_screen_get_default () != screen)
		envp = egg_screen_exec_environment (screen);

	gnome_desktop_item_drop_uri_list_with_env (launcher->ditem,
						   (const char *)selection_data->data,
						   0 /* flags */,
						   envp,
						   &error);
	g_strfreev (envp);
213

214 215 216 217 218 219
	if (error) {
		panel_error_dialog (
			launcher_get_screen (launcher),
			"cannot_launch_icon",
			_("Cannot launch icon\n%s"),
			error->message);
220
		g_clear_error (&error);
221
	}
222

223
	gtk_drag_finish (context, TRUE, FALSE, time);
224 225
}

226
static void
227 228
destroy_launcher (GtkWidget *widget,
		  Launcher  *launcher)
229
{
230 231 232 233 234 235 236
	launcher_properties_destroy (launcher);
}

void
launcher_properties_destroy (Launcher *launcher)
{
	GtkWidget *dialog;
237

238
	dialog = launcher->prop_dialog;
239 240
	launcher->prop_dialog = NULL;

241 242
	if (dialog)
		gtk_widget_destroy (dialog);
243 244 245
}

static void
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
246
free_launcher (gpointer data)
247 248 249
{
	Launcher *launcher = data;

250
	gnome_desktop_item_unref (launcher->ditem);
251
	launcher->ditem = NULL;
252

253
	if (launcher->revert_ditem != NULL)
254
		gnome_desktop_item_unref (launcher->revert_ditem);
255
	launcher->revert_ditem = NULL;
256

257
	g_free (launcher);
258 259
}

260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
void
panel_launcher_delete (Launcher *launcher)
{
	const char *location;

	location = gnome_desktop_item_get_location (launcher->ditem);

	if (location) {
		GnomeVFSResult result;

		result = gnome_vfs_unlink (location);
		if (result != GNOME_VFS_OK)
			g_warning ("Error unlinking '%s': %s\n", location,
				   gnome_vfs_result_to_string (result));
	}
}

277
static gboolean
278 279
is_this_drop_ok (GtkWidget      *widget,
		 GdkDragContext *context)
280
{
281 282 283
	static GdkAtom  text_uri_list = GDK_NONE;
	GList           *l;
	GtkWidget       *source;
284

285
	source = gtk_drag_get_source_widget (context);
286

287
	if (source == widget)
288 289
		return FALSE;

290
	if (!(context->actions & GDK_ACTION_COPY))
291 292
		return FALSE;

293
	if (!text_uri_list)
294 295
		text_uri_list = gdk_atom_intern ("text/uri-list", FALSE);

296 297
	for (l = context->targets; l; l = l->next) {
		if (GDK_POINTER_TO_ATOM (l->data) == text_uri_list)
298 299 300
			break;
	}

301
	return l ? TRUE : FALSE;
302 303 304 305 306 307 308 309
}

static void  
drag_leave_cb(GtkWidget	       *widget,
	      GdkDragContext   *context,
	      guint             time,
	      Launcher *launcher)
{
310
	button_widget_set_dnd_highlight(BUTTON_WIDGET(widget), FALSE);
311 312 313
}


314 315 316 317 318 319 320 321
static gboolean
drag_motion_cb(GtkWidget *widget,
	       GdkDragContext *context,
	       gint x,
	       gint y,
	       guint time,
	       Launcher *launcher)
{
322
	if ( ! is_this_drop_ok (widget, context))
323
		return FALSE;
324

325 326
	gdk_drag_status (context, GDK_ACTION_COPY, time);

327
	button_widget_set_dnd_highlight(BUTTON_WIDGET(widget), TRUE);
328 329 330

	return TRUE;
}
331 332

static gboolean
333 334 335 336 337 338
drag_drop_cb (GtkWidget	        *widget,
	      GdkDragContext    *context,
	      gint               x,
	      gint               y,
	      guint              time,
	      Launcher          *launcher)
339 340 341
{
	static GdkAtom text_uri_list = 0;

342
	if ( ! is_this_drop_ok (widget, context))
343 344
		return FALSE;

345
	if (text_uri_list == 0)
346 347
		text_uri_list = gdk_atom_intern ("text/uri-list", FALSE);

348
	gtk_drag_get_data (widget, context, text_uri_list, time);
349 350 351 352

	return TRUE;
}

353 354 355 356 357
enum {
	TARGET_ICON_INTERNAL,
	TARGET_URI_LIST
};

358

359
static void  
360 361 362 363 364 365
drag_data_get_cb (GtkWidget          *widget,
		  GdkDragContext     *context,
		  GtkSelectionData   *selection_data,
		  guint               info,
		  guint               time,
		  Launcher           *launcher)
366
{
367
	const char *location;
368
	
369
	g_return_if_fail (launcher != NULL);
370 371 372
	g_return_if_fail (launcher->ditem != NULL);

	location = gnome_desktop_item_get_location (launcher->ditem);
373

374
	if (!location) {
375
		launcher_save (launcher);
376 377
		location = gnome_desktop_item_get_location (launcher->ditem);
	}
378

379
	if (info == TARGET_URI_LIST) {
380 381 382 383 384 385
		if (location [0] != '/')
			gtk_selection_data_set (
				selection_data, selection_data->target, 8,
				(guchar *)location, strlen (location));
		else {
			char *uri;
386

387 388 389 390 391 392 393 394 395
			uri = g_strconcat ("file://", location, "\r\n", NULL);

			gtk_selection_data_set (
				selection_data, selection_data->target, 8,
				(guchar *)uri, strlen (uri));

			g_free (uri);
		}
	} else if (info == TARGET_ICON_INTERNAL)
396 397
		gtk_selection_data_set (selection_data,
					selection_data->target, 8,
398
					location, strlen (location));
399 400
}

401
static Launcher *
402
create_launcher (const char *location)
403
{
404 405 406
	GnomeDesktopItem *ditem;
	Launcher         *launcher;
	GError           *error = NULL;
407

408
        static GtkTargetEntry dnd_targets[] = {
409 410
		{ "application/x-panel-icon-internal", 0, TARGET_ICON_INTERNAL },
		{ "text/uri-list", 0, TARGET_URI_LIST }
411
	};
412

413 414 415
	if (!location) {
		g_printerr (_("No URI provided for panel launcher desktop file\n"));
		return NULL;
416
	}
417

418 419
	if (!strchr (location, G_DIR_SEPARATOR)) {
		char *path;
420

421
		path = panel_make_full_path (NULL, location);
422 423 424 425
		ditem = gnome_desktop_item_new_from_file (path, 0, &error);
		g_free (path);
	} else
		ditem = gnome_desktop_item_new_from_uri (location, 0, &error);
426 427 428

	if (!ditem) {
		g_printerr (_("Unable to open desktop file %s for panel launcher%s%s\n"),
429
			    location,
430 431 432 433 434
			    error ? ": " : "",
			    error ? error->message : "");
		if (error)
			g_error_free (error);

435
		return NULL; /*button is null*/
436
	}
437

438
	launcher = g_new0 (Launcher, 1);
439

440
	launcher->info = NULL;
441
	launcher->button = NULL;
442
	launcher->dedit = NULL;
443
	launcher->prop_dialog = NULL;
444
	launcher->destroy_handler = 0;
445

446
	/* Icon will be setup later */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
447 448 449
	launcher->button = button_widget_new (NULL /* icon */,
					      -1,
					      FALSE,
450
					      PANEL_ORIENTATION_TOP);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
451

452 453
	gtk_widget_show (launcher->button);

454
	/*A hack since this function only pretends to work on window
455 456 457 458
	  widgets (which we actually kind of are) this will select
	  some (already selected) events on the panel instead of
	  the launcher window (where they are also selected) but
	  we don't mind*/
459
	GTK_WIDGET_UNSET_FLAGS (launcher->button, GTK_NO_WINDOW);
460 461
	gtk_drag_source_set(launcher->button,
			    GDK_BUTTON1_MASK,
462 463 464
			    dnd_targets, 2,
			    GDK_ACTION_COPY | GDK_ACTION_MOVE);
	GTK_WIDGET_SET_FLAGS (launcher->button, GTK_NO_WINDOW);
465
	
466
	/*gtk_drag_dest_set (GTK_WIDGET (launcher->button),
467
			   GTK_DEST_DEFAULT_ALL,
468
			   dnd_targets, 2,
469 470 471
			   GDK_ACTION_COPY);*/
	gtk_drag_dest_set (GTK_WIDGET (launcher->button),
			   0, NULL, 0, 0);
472

Mark McLoughlin's avatar
Mark McLoughlin committed
473 474 475 476 477 478 479 480 481 482 483 484
	g_signal_connect (launcher->button, "drag_data_get",
			   G_CALLBACK (drag_data_get_cb), launcher);
	g_signal_connect (launcher->button, "drag_data_received",
			   G_CALLBACK (drag_data_received_cb), launcher);
	g_signal_connect (launcher->button, "drag_motion",
			   G_CALLBACK (drag_motion_cb), launcher);
	g_signal_connect (launcher->button, "drag_drop",
			   G_CALLBACK (drag_drop_cb), launcher);
	g_signal_connect (launcher->button, "drag_leave",
			   G_CALLBACK (drag_leave_cb), launcher);
	g_signal_connect (launcher->button, "clicked",
			  G_CALLBACK (launch_cb), launcher);
485

486 487 488 489
	launcher->destroy_handler =
			g_signal_connect (launcher->button, "destroy",
					  G_CALLBACK (destroy_launcher),
					  launcher);
490
	launcher->ditem = ditem;
491 492 493 494 495

	return launcher;
}

static void
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
496
setup_button (Launcher *launcher)
497
{
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
498 499 500 501
	const char *comment;
	const char *name;
	const char *docpath;
	char *str;
502
	const char *icon;
503
	char *unescaped_str;
504 505
	
	g_return_if_fail (launcher != NULL);
506

507 508 509 510
	name = gnome_desktop_item_get_localestring (launcher->ditem,
						    GNOME_DESKTOP_ITEM_NAME);
	comment = gnome_desktop_item_get_localestring (launcher->ditem,
						       GNOME_DESKTOP_ITEM_COMMENT);
511

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
512
	/* Setup tooltip */
513
	if ( ! string_empty (comment))
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
514 515 516
		str = g_strdup_printf ("%s\n%s", name, comment);
	else
		str = g_strdup (name);
517 518

	unescaped_str = gnome_vfs_unescape_string (str, NULL);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
519
	gtk_tooltips_set_tip (panel_tooltips, launcher->button,
520
			      unescaped_str, NULL);
521 522

	/* Setup accessible name */
523
	panel_a11y_set_atk_name_desc (launcher->button, unescaped_str, NULL);
524

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
525
	g_free (str);
526
	g_free (unescaped_str);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
527 528

	/* Setup icon */
529 530
	icon = gnome_desktop_item_get_string (launcher->ditem,
					      GNOME_DESKTOP_ITEM_ICON);
531
	button_widget_set_pixmap (BUTTON_WIDGET (launcher->button), icon);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
532 533 534

	/* Setup help */
	docpath = gnome_desktop_item_get_string (launcher->ditem,
535
						 "X-GNOME-DocPath");
536 537 538

	panel_applet_remove_callback (launcher->info, "help_on_app");

539
	if (docpath && *docpath != '\0') {
540 541
		char *title;

542
		title = g_strdup_printf (_("Help on %s _Application"), name);
543

544 545
		panel_applet_add_callback (launcher->info,
					   "help_on_app",
546 547
					   GTK_STOCK_HELP,
					   title);
548 549
		g_free (title);
	}
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
550 551 552 553 554 555 556 557
}


static void
properties_apply (Launcher *launcher)
{
	char *location;

558
	/* save location */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
559 560
	location = g_strdup (gnome_desktop_item_get_location (launcher->ditem));

561
	gnome_desktop_item_unref (launcher->ditem);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
562 563 564 565 566 567 568 569 570

	launcher->ditem =
		gnome_ditem_edit_get_ditem (GNOME_DITEM_EDIT (launcher->dedit));
	launcher->ditem = gnome_desktop_item_copy (launcher->ditem);

	/* restore location */
	gnome_desktop_item_set_location (launcher->ditem, location);
	g_free (location);

571 572
	launcher_save (launcher);

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
573 574
	/* Setup the button look */
	setup_button (launcher);
575

576
	/* FIXME_FOR_NEW_CONFIG: need to save changed settings here */
577 578
}

579
static void
580
properties_close_callback(GtkWidget *widget, gpointer data)
581
{
582
	Launcher *launcher = data;
583 584

	launcher->prop_dialog = NULL;
585
	launcher->dedit = NULL;
586

587
	if (launcher->revert_ditem != NULL)
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
588
		gnome_desktop_item_unref (launcher->revert_ditem);
589
	launcher->revert_ditem = NULL;
590 591
}

592 593 594 595 596 597 598 599
static void
launcher_changed (GtkObject *dedit, gpointer data)
{
	Launcher *launcher = data;

	properties_apply (launcher);
}

600 601 602 603 604 605 606 607 608 609 610
static void
set_revert_insensitive (GtkWidget *button,	
			gpointer   dummy)
{
     gtk_widget_set_sensitive (button, FALSE);
}

static void
set_revert_sensitive (GtkWidget *button,
		      gpointer   dummy)
{
611
     gtk_widget_set_sensitive (button, TRUE);
612 613
}

614
static void
615
window_response (GtkWidget *w, int response, gpointer data)
616
{
617 618
	Launcher *launcher = data;

619
	if (response == GTK_RESPONSE_HELP) {
620 621 622
		panel_show_help (
			gtk_window_get_screen (GTK_WINDOW (w)),
			"wgospanel.xml", "gospanel-52");
623
	} else if (response == REVERT_BUTTON) { /* revert */
624 625 626 627 628 629 630 631 632 633
		if (launcher->ditem != NULL)
			gnome_desktop_item_unref (launcher->ditem);
		launcher->ditem = gnome_desktop_item_copy (launcher->revert_ditem);

		/* We want to ignore the "changed" signal first */ 
		g_signal_handlers_disconnect_by_func (
				   G_OBJECT (GNOME_DITEM_EDIT(launcher->dedit)),
				   G_CALLBACK(launcher_changed),
				   launcher);

634
		gnome_ditem_edit_set_ditem (GNOME_DITEM_EDIT (launcher->dedit),
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
635
					    launcher->revert_ditem);
636 637 638 639 640 641 642 643 644 645

		/* connect the launcher_changed () callback for the "changed"
		 * signal again
		 */
		g_signal_connect (G_OBJECT (launcher->dedit), "changed",
				    G_CALLBACK (launcher_changed),
				    launcher);

		properties_apply (launcher);

646
	} else {
647
		gtk_widget_destroy (w);
648 649 650
	}
}

651
static GtkWidget *
652 653
create_properties_dialog (Launcher  *launcher,
			  GdkScreen *screen)
654
{
655
	GtkWidget *dialog;
656 657 658
        GtkWidget *help;
        GtkWidget *close;
        GtkWidget *revert;
659 660

	dialog = gtk_dialog_new ();
661

Frank Worsley's avatar
Frank Worsley committed
662
	gtk_window_set_title (GTK_WINDOW (dialog), _("Launcher Properties"));
663
	gtk_window_set_screen (GTK_WINDOW (dialog), screen);
664

665
	help = gtk_dialog_add_button (
666 667
			GTK_DIALOG (dialog), GTK_STOCK_HELP, GTK_RESPONSE_HELP);

668
	revert = gtk_dialog_add_button (
669
			GTK_DIALOG (dialog), GTK_STOCK_REVERT_TO_SAVED, REVERT_BUTTON);
670
        gtk_widget_set_sensitive (revert, FALSE);
671

672
	close = gtk_dialog_add_button (
673
			GTK_DIALOG (dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
674

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
675
	launcher->dedit = gnome_ditem_edit_new ();
676
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
677
			    launcher->dedit, TRUE, TRUE, 0);
678

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
679
	gtk_window_set_wmclass (GTK_WINDOW (dialog),
680
			       "launcher_properties", "Panel");
681
	
682
	if (launcher->revert_ditem != NULL)
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
683 684
		gnome_desktop_item_unref (launcher->revert_ditem);
	launcher->revert_ditem = gnome_desktop_item_copy (launcher->ditem);
685

686
	gnome_ditem_edit_set_ditem (GNOME_DITEM_EDIT (launcher->dedit),
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
687
				    launcher->ditem);
688

689 690 691
	g_signal_connect (launcher->dedit, "changed",
			  G_CALLBACK (launcher_changed),
			  launcher);
692

693 694
        g_signal_connect_swapped (launcher->dedit, "changed",
				  G_CALLBACK (set_revert_sensitive),
695
				  revert);
696 697 698 699

	g_signal_connect (dialog, "destroy",
			  G_CALLBACK (properties_close_callback),
			  launcher);
700

701
	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
702

703 704 705 706
	g_signal_connect (dialog, "response",
			  G_CALLBACK (window_response),
			  launcher);

707
	g_signal_connect (revert, "clicked",
708 709
			  G_CALLBACK (set_revert_insensitive),
			  NULL);
710

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
711
	gnome_ditem_edit_grab_focus (GNOME_DITEM_EDIT (launcher->dedit));
712

713 714 715
	return dialog;
}

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
716
void
717 718
launcher_properties (Launcher  *launcher,
		     GdkScreen *screen)
719
{
720
	if (launcher->prop_dialog != NULL) {
721 722
		gtk_window_set_screen (
			GTK_WINDOW (launcher->prop_dialog), screen);
723
		gtk_window_present (GTK_WINDOW (launcher->prop_dialog));
724 725 726
		return;
	}

727
	launcher->prop_dialog = create_properties_dialog (launcher, screen);
728
	gtk_widget_show_all (launcher->prop_dialog);
729
}
730

731
static Launcher *
732 733 734 735 736
load_launcher_applet (const char       *location,
		      PanelWidget      *panel,
		      int               pos,
		      gboolean          exactpos,
		      const char       *id)
737
{
738
	Launcher *launcher;
739

740
	launcher = create_launcher (location);
741

742 743
	if (!launcher)
		return NULL;
744

745 746 747 748 749
	launcher->info = panel_applet_register (launcher->button, launcher,
						free_launcher, panel, pos, 
						exactpos, PANEL_OBJECT_LAUNCHER,
						id);
	if (!launcher->info)
750
		return NULL;
751 752 753 754 755 756 757 758 759 760 761

	if (!commie_mode)
		panel_applet_add_callback (launcher->info,
					   "properties",
					   GTK_STOCK_PROPERTIES,
					   _("_Properties"));

	panel_applet_add_callback (launcher->info, "help", GTK_STOCK_HELP, _("_Help"));

	/* setup button according to ditem */
	setup_button (launcher);
762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796

	return launcher;
}

static void
panel_launcher_ensure_hoarded (Launcher   *launcher,
			       const char *launcher_location,
			       const char *id)
{
	GConfClient *client;
	const char  *profile;
	const char  *key;
	const char  *new_location = NULL;

	if (!strchr (launcher_location, G_DIR_SEPARATOR))
		return; /* already hoarded */
	
	if (!(new_location = panel_launcher_get_filename (launcher_location))) {
		const char *path;

		gnome_desktop_item_set_location (launcher->ditem, NULL);
		panel_launcher_save_ditem (launcher->ditem, launcher_get_screen (launcher));
		
		path = gnome_desktop_item_get_location (launcher->ditem);
		new_location = panel_launcher_get_filename (path);
	}

	if (!new_location)
		return;

	client  = panel_gconf_get_client ();
	profile = panel_profile_get_name ();

	key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, profile, id, "launcher_location");
	gconf_client_set_string (client, key, new_location, NULL);
797 798 799 800
}

void
launcher_load_from_gconf (PanelWidget *panel_widget,
801 802
			  int          position,
			  const char  *id)
803
{
804
	GConfClient *client;
805
	Launcher    *launcher;
806
	const char  *profile;
807
	const char  *key;
808 809
	char        *launcher_location;

810
	g_return_if_fail (panel_widget != NULL);
811
	g_return_if_fail (id != NULL);
812

813
	client  = panel_gconf_get_client ();
814 815 816 817
	profile = panel_profile_get_name ();

	key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, profile, id, "launcher_location");
	launcher_location = gconf_client_get_string (client, key, NULL);
818

819
	if (!launcher_location) {
820
		g_printerr (_("Key %s is not set, can't load launcher\n"), key);
821 822 823
		return;
	}
        
824 825 826 827 828 829 830 831
	launcher = load_launcher_applet (launcher_location,
					 panel_widget,
					 position,
					 TRUE,
					 id);

	if (launcher)
		panel_launcher_ensure_hoarded (launcher, launcher_location, id);
832

833
	g_free (launcher_location);
834 835
}

836
static void
837
really_add_launcher (GtkWidget *dialog, int response, gpointer data)
838
{
839
	GnomeDItemEdit *dedit = GNOME_DITEM_EDIT(data);
840 841
	int pos = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (dialog), "pos"));
	PanelWidget *panel = g_object_get_data (G_OBJECT (dialog), "panel");
842
	GnomeDesktopItem *ditem;
843
	
844
	if (response == GTK_RESPONSE_OK) {
845
		const char *location;
846

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
847
		ditem = gnome_ditem_edit_get_ditem (dedit);
848

849 850
		panel_launcher_save_ditem (ditem, gtk_window_get_screen (GTK_WINDOW (dialog)));
		location = gnome_desktop_item_get_location (ditem);
851

852
		panel_launcher_create (panel->toplevel, pos, location);
853
	} else if (response == GTK_RESPONSE_HELP) {
854 855 856
		panel_show_help (
			gtk_window_get_screen (GTK_WINDOW (dialog)),
			"wgospanel.xml", "gospanel-52");
857 858
		/* just return as we don't want to close */
		return;
859
	}
860

861 862 863 864
	panel->create_launcher_dialog_list = 
					g_slist_remove (panel->create_launcher_dialog_list, 
							dialog);

865
	gtk_widget_destroy (dialog);
866 867 868
}

void
869 870 871 872
ask_about_launcher (const char  *file,
		    PanelWidget *panel,
		    int          pos,
		    gboolean     exactpos)
873
{
874
	GtkWidget *dialog;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
875 876
	GnomeDItemEdit *dee;
	GnomeDesktopItem *ditem;
877

878 879
	dialog = gtk_dialog_new_with_buttons (
				_("Create Launcher"),
880
				GTK_WINDOW (panel->toplevel),
881 882 883 884 885
				0 /* flags */,
				GTK_STOCK_HELP, GTK_RESPONSE_HELP,
				GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
				GTK_STOCK_OK, GTK_RESPONSE_OK,
				NULL);
886

887 888
	gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);

889 890
	gtk_window_set_wmclass (GTK_WINDOW (dialog),
				"create_launcher", "Panel");
891
	
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
892
	dee = GNOME_DITEM_EDIT (gnome_ditem_edit_new ());
893
	gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
894
			    GTK_WIDGET (dee),
895
			    TRUE, TRUE, GNOME_PAD_SMALL);
896

897 898 899 900
	panel->create_launcher_dialog_list = 
					g_slist_append (panel->create_launcher_dialog_list,
							dialog);

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
901 902
	ditem = gnome_desktop_item_new ();
	gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_EXEC, file);
903
	gnome_desktop_item_set_entry_type (ditem, GNOME_DESKTOP_ITEM_TYPE_APPLICATION);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
904 905 906 907

	gnome_ditem_edit_set_ditem (dee, ditem);

	gnome_desktop_item_unref (ditem);
908
	
909 910 911 912
	g_object_set_data (G_OBJECT(dialog), "pos", GINT_TO_POINTER (pos));
	g_object_set_data (G_OBJECT(dialog), "exactpos",
			   GINT_TO_POINTER (exactpos));
	g_object_set_data (G_OBJECT (dialog), "panel", panel);
913

914 915
	g_signal_connect (G_OBJECT (dialog), "response",
			    G_CALLBACK (really_add_launcher),
916
			    dee);
917

918
	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
919

920
	gtk_widget_show_all (dialog);
921

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
922
	gnome_ditem_edit_grab_focus (dee);
923 924
}

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
925 926 927 928 929
static void
ditem_set_icon (GnomeDesktopItem *ditem, const char *icon)
{
	if (icon != NULL &&
	    icon[0] != G_DIR_SEPARATOR) {
930
		char *full = gnome_desktop_item_find_icon (panel_icon_theme,
931
							   icon,
932
							   48 /* desired size */,
933
							   0 /* flags */);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949
		if (full != NULL) {
			gnome_desktop_item_set_string (ditem,
						       GNOME_DESKTOP_ITEM_ICON,
						       full);
			g_free (full);
		} else {
			gnome_desktop_item_set_string (ditem,
						       GNOME_DESKTOP_ITEM_ICON,
						       icon);
		}
	} else {
		gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_ICON,
					       icon);
	}
}

950 951 952 953 954 955 956 957
void
panel_launcher_create_from_info (PanelToplevel *toplevel,
				 int            position,
				 gboolean       exec_info,
				 const char    *exec_or_uri,
				 const char    *name,
				 const char    *comment,
				 const char    *icon)
958
{
959
	GnomeDesktopItem *ditem;
960
	const char       *location;
961

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
962
	ditem = gnome_desktop_item_new ();
963

964 965
	/* set current language and the "C" locale to this name,
	 * this is kind of evil... */
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
966
	gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_NAME, name);
967 968 969 970
	gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_COMMENT, comment);
	gnome_desktop_item_set_localestring (ditem, GNOME_DESKTOP_ITEM_NAME, name);
	gnome_desktop_item_set_localestring (ditem, GNOME_DESKTOP_ITEM_COMMENT, comment);

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
971
	ditem_set_icon (ditem, icon);
972

973 974 975 976 977 978 979
	if (exec_info) {
		gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_EXEC, exec_or_uri);
		gnome_desktop_item_set_entry_type (ditem, GNOME_DESKTOP_ITEM_TYPE_APPLICATION);
	} else {
		gnome_desktop_item_set_string (ditem, GNOME_DESKTOP_ITEM_URL, exec_or_uri);
		gnome_desktop_item_set_entry_type (ditem, GNOME_DESKTOP_ITEM_TYPE_LINK);
	}
980

981 982
	panel_launcher_save_ditem (ditem, gtk_window_get_screen (GTK_WINDOW (toplevel)));
	location = gnome_desktop_item_get_location (ditem);
983

984
	panel_launcher_create (toplevel, position, location);
985

986
	gnome_desktop_item_unref (ditem);
987 988
}

989 990 991 992
void
panel_launcher_create (PanelToplevel *toplevel,
		       int            position,
		       const char    *location)
993
{
994 995 996 997
	GConfClient *client;
	const char  *profile;
	const char  *key;
	char        *id;
998

999
	g_return_if_fail (location != NULL);
1000

1001 1002
	client  = panel_gconf_get_client ();
	profile = panel_profile_get_name ();
1003

1004
	id = panel_profile_prepare_object (PANEL_OBJECT_LAUNCHER, toplevel, position, FALSE);
1005

1006 1007
	key = panel_gconf_full_key (PANEL_GCONF_OBJECTS, profile, id, "launcher_location");
	gconf_client_set_string (client, key, location, NULL);
1008

1009 1010
	/* frees id */
	panel_profile_add_to_list (PANEL_GCONF_OBJECTS, id);
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023

}

void
panel_launcher_create_copy (PanelToplevel *toplevel,
			    int            position,
			    const char    *location)
{
	GnomeVFSURI *source_uri;
	GnomeVFSURI *dest_uri;
	char        *new_location;
	const char  *filename;

1024
	new_location = panel_make_unique_path (NULL, ".desktop");
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041
	
	source_uri = gnome_vfs_uri_new (location);
	dest_uri   = gnome_vfs_uri_new (new_location);

	gnome_vfs_xfer_uri (source_uri,
			    dest_uri,
			    GNOME_VFS_XFER_FOLLOW_LINKS,
			    GNOME_VFS_XFER_ERROR_MODE_ABORT,
			    GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
			    NULL, NULL);

	gnome_vfs_uri_unref (source_uri);
	gnome_vfs_uri_unref (dest_uri);

	filename = panel_launcher_get_filename (new_location);
	panel_launcher_create (toplevel, position, filename);
	g_free (new_location);
1042 1043
}

1044
static void
1045 1046 1047
launcher_save (Launcher *launcher)
{
	g_return_if_fail (launcher != NULL);
1048
	g_return_if_fail (launcher->ditem != NULL);
1049

1050
	panel_launcher_save_ditem (launcher->ditem, launcher_get_screen (launcher));
1051
}
1052 1053 1054 1055

Launcher *
find_launcher (const char *path)
{
1056
	GSList *l;
1057 1058 1059

	g_return_val_if_fail (path != NULL, NULL);

1060 1061
	for (l = panel_applet_list_applets (); l; l = l->next) {
		AppletInfo *info = l->data;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1062 1063
		Launcher *launcher;
		const char *location;
1064

1065
		if (info->type != PANEL_OBJECT_LAUNCHER)
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077
			continue;

		launcher = info->data;

		if (launcher->ditem == NULL)
			continue;

		location = gnome_desktop_item_get_location (launcher->ditem);

		if (location != NULL &&
		    strcmp (location, path) == 0)
			return launcher;
1078 1079 1080 1081
	}

	return NULL;
}
1082 1083

void
1084 1085
launcher_show_help (Launcher  *launcher,
		    GdkScreen *screen)
1086 1087 1088 1089 1090 1091 1092 1093
{
	GError     *error = NULL;
	const char *docpath;

	if (!launcher->ditem)
		return;

	docpath = gnome_desktop_item_get_string (
1094
				launcher->ditem, "X-GNOME-DocPath");
1095
	panel_show_gnome_kde_help (screen, docpath, &error);
1096 1097
	if (error) {
		panel_error_dialog (
1098
			screen,
1099 1100 1101 1102 1103 1104
			"cannot_show_gnome_kde_help",
			_("<b>Cannot display help document</b>\n\nDetails: %s"),
			error->message);
		g_error_free (error);
	}
}