panel.c 29.4 KB
Newer Older
1
/* Gnome panel: Initialization routines
2 3
 * (C) 1997,1998,1999,2000 the Free Software Foundation
 * (C) 2000 Eazel, Inc.
Elliot Lee's avatar
Elliot Lee committed
4
 *
5 6 7
 * Authors: Federico Mena
 *          Miguel de Icaza
 *          George Lebl
Elliot Lee's avatar
Elliot Lee committed
8 9
 */

10
#include <config.h>
Elliot Lee's avatar
Elliot Lee committed
11
#include <string.h>
12
#include <signal.h>
13
#include <unistd.h>
14
#include <sys/types.h>
15
#include <sys/stat.h>
16
#include <sys/wait.h>
Mark McLoughlin's avatar
Mark McLoughlin committed
17

18 19
#include <gdk/gdkkeysyms.h>

Mark McLoughlin's avatar
Mark McLoughlin committed
20
#include <libgnome/libgnome.h>
21
#include <libbonobo.h>
22
#include <libgnomevfs/gnome-vfs-uri.h>
23
#include <libgnomevfs/gnome-vfs-ops.h>
24
#include <libgnomevfs/gnome-vfs-mime.h>
25 26
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
#include <libgnomevfs/gnome-vfs-file-info.h>
27
#include <libgnomeui/gnome-window-icon.h>
28

Mark McLoughlin's avatar
Mark McLoughlin committed
29 30 31
#include "panel.h"

#include "applet.h"
32
#include "drawer.h"
Mark McLoughlin's avatar
Mark McLoughlin committed
33 34 35 36 37 38 39
#include "button-widget.h"
#include "distribution.h"
#include "launcher.h"
#include "menu-fentry.h"
#include "menu-util.h"
#include "menu.h"
#include "panel-util.h"
40 41
#include "panel-config-global.h"
#include "panel-gconf.h"
42
#include "panel-profile.h"
43
#include "panel-applet-frame.h"
44
#include "panel-action-button.h"
45
#include "panel-menu-bar.h"
46
#include "panel-compatibility.h"
47 48 49 50
#include "panel-multiscreen.h"
#include "panel-toplevel.h"
#include "panel-menu-button.h"
#include "panel-globals.h"
Owen Taylor's avatar
Owen Taylor committed
51 52 53

enum {
	TARGET_URL,
54
	TARGET_NETSCAPE_URL,
55 56
	TARGET_DIRECTORY,
	TARGET_COLOR,
57
	TARGET_APPLET,
58
	TARGET_APPLET_INTERNAL,
59
	TARGET_ICON_INTERNAL,
60 61
	TARGET_BGIMAGE,
	TARGET_BACKGROUND_RESET,
Owen Taylor's avatar
Owen Taylor committed
62 63
};

64
/*we call this recursively*/
65
static void orient_change_foreach(GtkWidget *w, gpointer data);
66

67
void
68 69
orientation_change (AppletInfo  *info,
		    PanelWidget *panel)
70
{
71 72 73
	PanelOrientation orientation;

	orientation = panel_widget_get_applet_orientation (panel);
74

75
	switch (info->type) {
76 77 78
	case PANEL_OBJECT_BONOBO:
		panel_applet_frame_change_orientation (
				PANEL_APPLET_FRAME (info->widget), orientation);
79
		break;
80 81 82
	case PANEL_OBJECT_MENU:
		panel_menu_button_change_orientation (PANEL_MENU_BUTTON (info->widget),
						      orientation);
83
		break;
84
	case PANEL_OBJECT_DRAWER: {
85
		Drawer      *drawer = info->data;
86 87 88
		PanelWidget *panel_widget;

		panel_widget = panel_toplevel_get_panel_widget (drawer->toplevel);
89

90 91 92
		set_drawer_applet_orientation (drawer, orientation);
		gtk_widget_queue_resize (GTK_WIDGET (drawer->toplevel));
		gtk_container_foreach (GTK_CONTAINER (panel_widget),
93
				       orient_change_foreach,
94
				       panel_widget);
95
		}
96 97 98
		break;
	default:
		break;
99 100 101
	}
}

102
static void
103
orient_change_foreach(GtkWidget *w, gpointer data)
104
{
105
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
106
	PanelWidget *panel = data;
107
	
108
	orientation_change(info,panel);
109 110
}

111

112
static void
113
panel_orient_change (GtkWidget *widget, gpointer data)
114
{
115 116
	gtk_container_foreach(GTK_CONTAINER(widget),
			      orient_change_foreach,
117
			      widget);
118 119
}

120 121 122 123
/*we call this recursively*/
static void size_change_foreach(GtkWidget *w, gpointer data);

void
Mark McLoughlin's avatar
Mark McLoughlin committed
124 125
size_change (AppletInfo  *info,
	     PanelWidget *panel)
126
{
127
	if (info->type == PANEL_OBJECT_BONOBO)
Mark McLoughlin's avatar
Mark McLoughlin committed
128
		panel_applet_frame_change_size (
129
			PANEL_APPLET_FRAME (info->widget), panel->sz);
130 131 132 133 134
}

static void
size_change_foreach(GtkWidget *w, gpointer data)
{
135
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
136 137 138 139 140 141 142
	PanelWidget *panel = data;
	
	size_change(info,panel);
}


static void
143
panel_size_change (GtkWidget *widget, gpointer data)
144 145 146 147 148
{
	gtk_container_foreach(GTK_CONTAINER(widget), size_change_foreach,
			      widget);
}

149
#ifdef FIXME_FOR_NEW_CONFIG
150
void
151
back_change (AppletInfo  *info,
Mark McLoughlin's avatar
Mark McLoughlin committed
152
	     PanelWidget *panel)
153
{
154
	if (info->type == PANEL_OBJECT_BONOBO)
155
		panel_applet_frame_change_background (
156
			PANEL_APPLET_FRAME (info->widget), panel->background.type);
Elliot Lee's avatar
Elliot Lee committed
157 158 159
}

static void
Mark McLoughlin's avatar
Mark McLoughlin committed
160 161
back_change_foreach (GtkWidget   *widget,
		     PanelWidget *panel)
Elliot Lee's avatar
Elliot Lee committed
162
{
Mark McLoughlin's avatar
Mark McLoughlin committed
163 164
	AppletInfo *info;

165
	info = g_object_get_data (G_OBJECT (widget), "applet_info");
166

Mark McLoughlin's avatar
Mark McLoughlin committed
167
	back_change (info, panel);
Elliot Lee's avatar
Elliot Lee committed
168 169
}

170
static void
171
panel_back_change (GtkWidget *widget, gpointer data)
172
{
Mark McLoughlin's avatar
Mark McLoughlin committed
173 174 175
	gtk_container_foreach (GTK_CONTAINER (widget),
			       (GtkCallback) back_change_foreach,
			       widget);
176

177
#ifdef FIXME_FOR_NEW_CONFIG
178
	/*update the configuration box if it is displayed*/
179
	update_config_back(PANEL_WIDGET(widget));
180
#endif /* FIXME_FOR_NEW_CONFIG */
181 182
}
#endif
183

184 185
static void
panel_applet_added(GtkWidget *widget, GtkWidget *applet, gpointer data)
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
186
{
187 188
	PanelToplevel *toplevel;
	AppletInfo    *info;
189

190 191 192
	toplevel = PANEL_WIDGET (widget)->toplevel;
	info = g_object_get_data (G_OBJECT (applet), "applet_info");

193 194
	orientation_change(info,PANEL_WIDGET(widget));
	size_change(info,PANEL_WIDGET(widget));
195
#ifdef FIXME_FOR_NEW_CONFIG
196
	back_change(info,PANEL_WIDGET(widget));
197
#endif
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
198 199
}

200
static void
201
panel_applet_removed(GtkWidget *widget, GtkWidget *applet, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
202
{
203 204
	PanelToplevel *toplevel;
	AppletInfo    *info;
205

206 207 208 209
	toplevel = PANEL_WIDGET (widget)->toplevel;
	info = g_object_get_data (G_OBJECT (applet), "applet_info");

	if (info->type == PANEL_OBJECT_DRAWER) {
210
		Drawer *drawer = info->data;
211 212 213

		if (drawer->toplevel)
			panel_toplevel_queue_auto_hide (toplevel);
214
	}
215
}
Elliot Lee's avatar
Elliot Lee committed
216

217 218 219 220 221 222 223 224 225 226 227
static gboolean
deactivate_idle (gpointer data)
{
	PanelData *pd = data;
	pd->deactivate_idle = 0;

	pd->insertion_pos = -1;

	return FALSE;
}

Elliot Lee's avatar
Elliot Lee committed
228
static void
229
menu_deactivate(GtkWidget *w, PanelData *pd)
Elliot Lee's avatar
Elliot Lee committed
230
{
231 232
	if (pd->deactivate_idle == 0)
		pd->deactivate_idle = g_idle_add (deactivate_idle, pd);
233

234
	panel_toplevel_unblock_auto_hide (PANEL_TOPLEVEL (pd->panel));
235 236
}

237
static void
238
panel_remove_applets (PanelWidget *panel)
239
{
240
	GList *l;
241

242
	for (l = panel->applet_list; l; l = l->next) {
Mark McLoughlin's avatar
Mark McLoughlin committed
243
		AppletData *applet_data = l->data;
244
		AppletInfo *info;
245

Mark McLoughlin's avatar
Mark McLoughlin committed
246 247
		info = g_object_get_data (
				G_OBJECT (applet_data->applet), "applet_info");
248

249
		if (info && info->type == PANEL_OBJECT_LAUNCHER)
250 251
			launcher_properties_destroy (info->data);
			
252 253 254
	}
}

255 256 257 258 259 260 261 262 263 264 265 266 267
static void
panel_remove_open_create_launcher_dialogs (PanelWidget *panel)
{
	GSList *l;

	for (l = panel->create_launcher_dialog_list; l ; l = l->next) {
		GtkWidget *dialog = l->data;

		if (GTK_IS_WIDGET (dialog))
			gtk_widget_destroy (dialog);
	}
}

268
static void
269 270
panel_destroy (PanelToplevel *toplevel,
	       PanelData     *pd)
271
{
272
	PanelWidget *panel_widget;
273

274
	panel_widget = panel_toplevel_get_panel_widget (toplevel);
275

276
	panel_remove_applets (panel_widget);
277

278
	panel_remove_open_create_launcher_dialogs (panel_widget);
279

280 281
	if (pd->menu)
		g_object_unref (pd->menu);
282
	pd->menu = NULL;
283

284 285
	pd->panel = NULL;

286 287 288 289
	if (pd->deactivate_idle != 0)
		g_source_remove (pd->deactivate_idle);
	pd->deactivate_idle = 0;

290
	g_object_set_data (G_OBJECT (toplevel), "PanelData", NULL);
291

292 293
	panel_list = g_slist_remove (panel_list, pd);
	g_free (pd);
294 295
}

296
static void
297
panel_applet_move(PanelWidget *panel, GtkWidget *widget, gpointer data)
298
{
299 300 301 302 303 304
	AppletInfo *info;

	info = g_object_get_data (G_OBJECT (widget), "applet_info");

	g_return_if_fail (info);

305
	panel_applet_save_position (info, info->id, FALSE);
306 307
}

308
static GtkWidget *
309
panel_menu_get (PanelWidget *panel, PanelData *pd)
310
{
311
	if (pd->menu != NULL)
312
		return pd->menu;
313
	
314 315
	pd->menu = g_object_ref (create_panel_context_menu (panel));
	gtk_object_sink (GTK_OBJECT (pd->menu));
316 317
	g_signal_connect (G_OBJECT (pd->menu), "deactivate",
			  G_CALLBACK (menu_deactivate), pd);
318
	return pd->menu;
319 320
}

321
GtkWidget *
322
make_popup_panel_menu (PanelWidget *panel_widget)
323 324 325 326
{
	PanelData *pd;
	GtkWidget *menu;

327 328 329 330 331 332 333
	if (!panel_widget) {
		PanelToplevel *toplevel;

		toplevel = PANEL_TOPLEVEL (((PanelData *) panel_list->data)->panel);

		panel_widget = panel_toplevel_get_panel_widget (toplevel);
	}
334

335 336 337
	pd = g_object_get_data (G_OBJECT (panel_widget->toplevel), "PanelData");
	menu = panel_menu_get (panel_widget, pd);
	g_object_set_data (G_OBJECT (menu), "menu_panel", panel_widget);
338

339
	return menu;
340
}
341 342

static gboolean
343 344 345
panel_popup_menu (PanelToplevel *toplevel,
		  guint          button,
		  guint32        activate_time)
346
{
347 348 349 350
	PanelWidget *panel_widget;
	GtkWidget   *menu;
	PanelData   *panel_data;
	int          x = -1, y = 1;
351

352 353
	panel_widget = panel_toplevel_get_panel_widget (toplevel);
	panel_data   = g_object_get_data (G_OBJECT (toplevel), "PanelData");
354

355
	gtk_widget_get_pointer (GTK_WIDGET (panel_widget), &x, &y);
356

357 358 359 360 361 362
	if (panel_widget->orient == GTK_ORIENTATION_HORIZONTAL)
		panel_data->insertion_pos = x;
	else
		panel_data->insertion_pos = y;
	
	menu = make_popup_panel_menu (panel_widget);
363

364
	panel_toplevel_block_auto_hide (toplevel);
365

366 367
	gtk_menu_set_screen (GTK_MENU (menu),
			     gtk_window_get_screen (GTK_WINDOW (toplevel)));
368

369 370
	gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
			panel_menu_position, panel_widget, button, activate_time);
371 372

	return TRUE;
373
}
374 375

static gboolean
376
panel_popup_menu_signal (PanelToplevel *toplevel)
377
{
378
	return panel_popup_menu (toplevel, 3, GDK_CURRENT_TIME);
379 380
}

381
static gboolean
382 383
panel_button_press_event (PanelToplevel  *toplevel,
			  GdkEventButton *event)
384
{
385
	if (event->button != 3)
386 387
		return FALSE;

388
	return panel_popup_menu (toplevel, event->button, event->time);
389 390
}

391
static gboolean
392 393
panel_key_press_event (GtkWidget   *widget,
		       GdkEventKey *event)
394
{
395 396 397 398 399 400
	/*
  	 * If the focus widget is a GtkSocket, i.e. the
	 * focus is in an applet in another process, then key 
	 * bindings do not work. We get around this by
	 * activating the key bindings here.
	 */ 
401 402
	if (GTK_IS_SOCKET (GTK_WINDOW (widget)->focus_widget) &&
	    event->keyval == GDK_F10 && event->state == GDK_CONTROL_MASK)
403 404 405
		return gtk_bindings_activate (GTK_OBJECT (widget),
					      event->keyval,
					      event->state);
406

407 408
	return FALSE;
}
409

410 411 412
static void
set_background_image_from_uri (PanelToplevel *toplevel,
			       const char    *uri)
413
{
414
	char *image;
415

416 417
	if (!(image = g_filename_from_uri (uri, NULL, NULL)))
		return;
418

419 420
	panel_profile_set_background_image (toplevel, image);
	panel_profile_set_background_type (toplevel, PANEL_BACK_IMAGE);
421

422
	g_free (image);
423 424
}

425 426 427
static void
set_background_color (PanelToplevel *toplevel,
		      guint16       *dropped)
428
{
429
	PanelColor color;
430

431 432
	if (!dropped)
		return;
433

434 435 436 437
	color.gdk.red   = dropped [0];
	color.gdk.green = dropped [1];
	color.gdk.blue  = dropped [2];
	color.alpha     = 65535;
438

439 440
	panel_profile_set_background_color (toplevel, &color);
	panel_profile_set_background_type (toplevel, PANEL_BACK_COLOR);
Arturo Espinosa's avatar
Arturo Espinosa committed
441 442
}

443
static void
444 445 446
drop_url (PanelWidget *panel,
	  int          position,
	  const char  *url)
447
{
448
	char *comment;
449 450 451

	g_return_if_fail (url != NULL);

452 453 454 455 456 457
	comment = g_strdup_printf (_("Open URL: %s"), url);

	panel_launcher_create_from_info (
		panel->toplevel, position, FALSE, url, url, comment, "gnome-globe.png");

	g_free (comment);
458 459 460
}

static void
461 462 463
drop_menu (PanelWidget *panel,
	   int          position,
	   const char  *menu_path)
464
{
465
	panel_menu_button_create (panel->toplevel, position, menu_path, menu_path != NULL);
466 467
}

468 469
static void
drop_nautilus_uri (PanelWidget *panel,
470 471 472
		   int          position,
		   const char  *uri,
		   const char  *icon)
473
{
474 475
	char *quoted;
	char *exec;
476
	char *base;
477 478 479

	quoted = g_shell_quote (uri);
	exec = g_strdup_printf ("nautilus %s", quoted);
480 481 482 483
	g_free (quoted);

	base = g_path_get_basename (uri);

484 485 486
	panel_launcher_create_from_info (
		panel->toplevel, position, TRUE, exec, base, uri, icon);

487 488 489 490
	g_free (exec);
	g_free (base);
}

491 492 493 494 495
static void
drop_directory (PanelWidget *panel, int pos, const char *dir)
{
	char *tmp;

496 497 498
	/* not filename, but path, these are uris, not local
	 * files */
	tmp = g_build_path ("/", dir, ".directory", NULL);
499
	if (panel_uri_exists (tmp)) {
500 501 502 503 504 505
		g_free (tmp);
		drop_menu (panel, pos, dir);
		return;
	}
	g_free (tmp);

506
	tmp = g_build_path ("/", dir, ".order", NULL);
507
	if (panel_uri_exists (tmp)) {
508 509 510 511 512 513
		g_free (tmp);
		drop_menu (panel, pos, dir);
		return;
	}
	g_free (tmp);

514
	if (panel_is_program_in_path ("nautilus")) {
515
		/* nautilus */
516
		drop_nautilus_uri (panel, pos, dir, "gnome-folder.png");
517
	} else {
518
		drop_menu (panel, pos, dir);
519 520 521
	}
}

522
static void
523
drop_urilist (PanelWidget *panel, int pos, char *urilist)
524 525 526
{
	GList *li, *files;

527
	files = gnome_vfs_uri_list_parse (urilist);
528

529 530 531
	for (li = files; li; li = li->next) {
		GnomeVFSURI *vfs_uri = li->data;
		gchar *uri = gnome_vfs_uri_to_string (vfs_uri, GNOME_VFS_URI_HIDE_NONE);
532
		const char *mimetype;
533 534
		char *basename;
		char *dirname;
535
		char *filename;
536
		GnomeVFSFileInfo *info;
537

538 539 540 541 542 543 544
		if (strncmp (uri, "http:", strlen ("http:")) == 0 ||
		    strncmp (uri, "https:", strlen ("https:")) == 0 ||
		    strncmp (uri, "ftp:", strlen ("ftp:")) == 0 ||
		    strncmp (uri, "gopher:", strlen ("gopher:")) == 0 ||
		    strncmp (uri, "ghelp:", strlen ("ghelp:")) == 0 ||
		    strncmp (uri, "man:", strlen ("man:")) == 0 ||
		    strncmp (uri, "info:", strlen ("info:")) == 0) {
545 546 547
			/* FIXME: probably do this only on link,
			 * in fact, on link always set up a link,
			 * on copy do all the other stuff.  Or something. */
548
			drop_url (panel, pos, uri);
549 550 551
			continue;
		}

552 553 554 555
		mimetype = gnome_vfs_mime_type_from_name (uri);
		basename = gnome_vfs_uri_extract_short_path_name (vfs_uri);
		dirname = gnome_vfs_uri_extract_dirname (vfs_uri);
		info = gnome_vfs_file_info_new ();
556

557 558 559 560
		if (gnome_vfs_get_file_info_uri (vfs_uri, info,
						 GNOME_VFS_FILE_INFO_DEFAULT) != GNOME_VFS_OK) {
			gnome_vfs_file_info_unref (info);
			info = NULL;
561 562
		}

563 564 565 566 567
		if (mimetype &&
		    !strncmp (mimetype, "image", sizeof ("image") - 1))
			set_background_image_from_uri (panel->toplevel, uri);

		else if (basename != NULL &&
568 569 570 571 572 573 574
			   strcmp (basename, ".directory") == 0 &&
			   dirname != NULL) {
			/* This is definately a menu */
			char *menu_uri = g_strconcat (vfs_uri->method_string, ":",
						      dirname, NULL);
			drop_menu (panel, pos, menu_uri);
			g_free (menu_uri);
575
		} else if (mimetype != NULL &&
576
			   (strcmp(mimetype, "application/x-gnome-app-info") == 0 ||
577
			    strcmp(mimetype, "application/x-desktop") == 0 ||
578 579
			    strcmp(mimetype, "application/x-kde-app-info") == 0))
			panel_launcher_create (panel->toplevel, pos, uri);
580
			
581
		else if (info != NULL &&
582 583 584 585 586 587 588 589
			   info->type == GNOME_VFS_FILE_TYPE_DIRECTORY) {
			drop_directory (panel, pos, uri);
		} else if (info != NULL &&
			   info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS &&
			   info->permissions &
			     (GNOME_VFS_PERM_USER_EXEC |
			      GNOME_VFS_PERM_GROUP_EXEC |
			      GNOME_VFS_PERM_OTHER_EXEC) &&
590
			   (filename = g_filename_from_uri (uri, NULL, NULL)) != NULL) {
591 592
			/* executable and local, so add a launcher with
			 * it */
593
			ask_about_launcher (filename, panel, pos, TRUE);
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
			g_free (filename);
		} else {
			/* FIXME: add a launcher that will launch the app
			 * associated with this file */
			/* FIXME: For now just add a launcher that launches
			 * nautilus on this uri */
			const char *icon = NULL;
			if (mimetype != NULL)
		        	icon = gnome_vfs_mime_get_icon (mimetype);
			if (icon == NULL)
				icon = "gnome-unknown.png";
			drop_nautilus_uri (panel, pos, uri, icon);
		}
		if (info != NULL)
			gnome_vfs_file_info_unref (info);
		g_free (basename);
		g_free (dirname);
611
		g_free (uri);
612 613
	}

614
	gnome_vfs_uri_list_free (files);
615 616 617
}

static void
618 619 620 621
drop_internal_icon (PanelWidget *panel,
		    int          pos,
		    const char  *icon_name,
		    int          action)
622
{
623
	Launcher *old_launcher = NULL;
624

625
	if (!icon_name)
626
		return;
627

628
	if (action == GDK_ACTION_MOVE)
629
		old_launcher = find_launcher (icon_name);
630
	
631
	panel_launcher_create_copy (panel->toplevel, pos, icon_name);
632

633 634 635 636 637
	if (old_launcher && old_launcher->button) {
		if (old_launcher->prop_dialog) {
			g_signal_handler_disconnect (old_launcher->button,
						     old_launcher->destroy_handler);
			launcher_properties_destroy (old_launcher);
638
		}
639
		panel_profile_delete_object (old_launcher->info);
640 641 642
	}
}

643
static void
644
move_applet (PanelWidget *panel, int pos, int applet_index)
645
{
646 647 648 649 650 651
	GSList     *applet_list;
	AppletInfo *info;

	applet_list = panel_applet_list_applets ();

	info = g_slist_nth_data (applet_list, applet_index);
652 653 654 655 656 657 658

	if (pos < 0)
		pos = 0;

	if (info != NULL &&
	    info->widget != NULL &&
	    info->widget->parent != NULL &&
659
	    PANEL_IS_WIDGET (info->widget->parent)) {
660
		GSList *forb;
661 662
		forb = g_object_get_data (G_OBJECT (info->widget),
					  PANEL_APPLET_FORBIDDEN_PANELS);
663 664 665 666 667 668 669 670
		if ( ! g_slist_find (forb, panel))
			panel_widget_reparent (PANEL_WIDGET (info->widget->parent),
					       panel,
					       info->widget,
					       pos);
	}
}

671
static void
672 673
drop_internal_applet (PanelWidget *panel, int pos, const char *applet_type,
		      int action)
674
{
675
	int applet_index = -1;
676 677
	gboolean remove_applet = FALSE;

678 679 680
	if (applet_type == NULL)
		return;

681 682
	if (sscanf (applet_type, "MENU:%d", &applet_index) == 1 ||
	    sscanf (applet_type, "DRAWER:%d", &applet_index) == 1) {
683
		if (action != GDK_ACTION_MOVE)
Mark McLoughlin's avatar
Mark McLoughlin committed
684
			g_warning ("Only MOVE supported for menus/drawers");
685
		move_applet (panel, pos, applet_index);
686 687

	} else if (strncmp (applet_type, "MENU:", strlen("MENU:")) == 0) {
688 689 690
		const char *menu = &applet_type[strlen ("MENU:")];
		if (strcmp (menu, "MAIN") == 0)
			drop_menu (panel, pos, NULL);
691
		else
692
			drop_menu (panel, pos, menu);
693

694
	} else if (!strcmp (applet_type, "DRAWER:NEW"))
695
		panel_drawer_create (panel->toplevel, pos, NULL, FALSE, NULL);
696

697 698
	else if (!strncmp (applet_type, "ACTION:", strlen ("ACTION:")))
		remove_applet = panel_action_button_load_from_drag (
699 700 701 702
						panel->toplevel,
						pos,
						applet_type,
						&applet_index);
703

704
	else if (!strcmp (applet_type, "MENUBAR:NEW"))
705
		panel_menu_bar_create (panel->toplevel, pos);
706

707 708
	else if (!strcmp(applet_type,"LAUNCHER:ASK"))
		ask_about_launcher (NULL, panel, pos, TRUE);
709 710 711

	if (remove_applet &&
	    action == GDK_ACTION_MOVE) {
712 713
		AppletInfo *info;
		GSList     *applet_list;
714

715
		applet_list = panel_applet_list_applets ();
716

717
		info = g_slist_nth_data (applet_list, applet_index);
718

719 720 721
		if (info)
			panel_profile_delete_object (info);
	}
722 723
}

724 725 726 727 728 729 730 731 732
static GtkTargetList *
get_target_list (void)
{
	static GtkTargetEntry drop_types [] = {
		{ "text/uri-list",                       0, TARGET_URL },
		{ "x-url/http",                          0, TARGET_NETSCAPE_URL },
		{ "x-url/ftp",                           0, TARGET_NETSCAPE_URL },
		{ "_NETSCAPE_URL",                       0, TARGET_NETSCAPE_URL },
		{ "application/x-panel-directory",       0, TARGET_DIRECTORY },
733
		{ "application/x-panel-applet-iid",      0, TARGET_APPLET },
734 735 736
		{ "application/x-panel-applet-internal", 0, TARGET_APPLET_INTERNAL },
		{ "application/x-panel-icon-internal",   0, TARGET_ICON_INTERNAL },
		{ "application/x-color",                 0, TARGET_COLOR },
737 738
		{ "property/bgimage",                    0, TARGET_BGIMAGE },
		{ "x-special/gnome-reset-background",    0, TARGET_BACKGROUND_RESET },
739 740 741 742 743 744 745 746 747 748 749 750
	};
	static GtkTargetList *target_list = NULL;

	if (!target_list) {
		gint length = sizeof (drop_types) / sizeof (drop_types [0]);

		target_list = gtk_target_list_new (drop_types, length);
	}

	return target_list;
}

751 752 753 754 755
gboolean
panel_check_dnd_target_data (GtkWidget      *widget,
			     GdkDragContext *context,
			     guint          *ret_info,
			     GdkAtom        *ret_atom)
756
{
757
	GList *l;
758 759

	g_return_val_if_fail (widget, FALSE);
760

761
	if (!PANEL_IS_TOPLEVEL  (widget) &&
762
	    !BUTTON_IS_WIDGET (widget))
763
		return FALSE;
764

765
	if (!(context->actions & (GDK_ACTION_COPY|GDK_ACTION_MOVE)))
766 767
		return FALSE;

768 769 770 771 772 773 774 775 776 777 778 779
	for (l = context->targets; l; l = l->next) {
		GdkAtom atom;
		guint   info;

		atom = GDK_POINTER_TO_ATOM (l->data);

		if (gtk_target_list_find (get_target_list (), atom, &info)) {
			if (ret_info)
				*ret_info = info;

			if (ret_atom)
				*ret_atom = atom;
780 781 782
			break;
		}
	}
783 784

	return l ? TRUE : FALSE;
785 786
}

787
static void
788 789 790
do_highlight (GtkWidget *widget, gboolean highlight)
{
	gboolean have_drag;
791 792 793 794 795

	/* FIXME: what's going on here ? How are we highlighting
	 *        the toplevel widget ? I don't think we are ...
	 */

796 797
	have_drag = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
							"have-drag"));
798 799
	if(highlight) {
		if(!have_drag) {
800 801
			g_object_set_data (G_OBJECT (widget), "have-drag",
					   GINT_TO_POINTER (TRUE));
802 803 804 805
			gtk_drag_highlight (widget);
		}
	} else {
		if(have_drag) {
806 807
			g_object_set_data (G_OBJECT (widget),
					   "have-drag", NULL);
808 809 810 811 812
			gtk_drag_unhighlight (widget);
		}
	}
}

813 814 815 816 817
gboolean
panel_check_drop_forbidden (PanelWidget    *panel,
			    GdkDragContext *context,
			    guint           info,
			    guint           time_)
818
{
819
	if (!panel)
820 821
		return FALSE;

822 823 824 825
	if (info == TARGET_APPLET_INTERNAL) {
		GtkWidget *source_widget;

		source_widget = gtk_drag_get_source_widget (context);
826 827

		if (BUTTON_IS_WIDGET (source_widget)) {
828
			GSList *forb;
829

830 831
			forb = g_object_get_data (G_OBJECT (source_widget),
						  PANEL_APPLET_FORBIDDEN_PANELS);
832 833

			if (g_slist_find (forb, panel))
834 835 836 837
				return FALSE;
		}
	}

838 839
	if (info == TARGET_ICON_INTERNAL ||
	    info == TARGET_APPLET_INTERNAL) {
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
		if (context->actions & GDK_ACTION_MOVE)
			gdk_drag_status (context, GDK_ACTION_MOVE, time_);
		else
			gdk_drag_status (context, context->suggested_action, time_);

	} else if (context->actions & GDK_ACTION_COPY)
		gdk_drag_status (context, GDK_ACTION_COPY, time_);
	else
		gdk_drag_status (context, context->suggested_action, time_);

	return TRUE;

}

static gboolean
drag_motion_cb (GtkWidget	   *widget,
		GdkDragContext     *context,
		gint                x,
		gint                y,
		guint               time)
{
861 862 863 864 865
	PanelToplevel *toplevel;
	PanelWidget   *panel_widget;
	guint          info;

	g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE);
866 867 868 869

	if (!panel_check_dnd_target_data (widget, context, &info, NULL))
		return FALSE;

870 871
	toplevel = PANEL_TOPLEVEL (widget);
	panel_widget = panel_toplevel_get_panel_widget (toplevel);
872

873
	if (!panel_check_drop_forbidden (panel_widget, context, info, time))
874
		return FALSE;
875

876
	do_highlight (widget, TRUE);
877

878 879
	panel_toplevel_unhide (toplevel);
	panel_toplevel_queue_auto_hide (toplevel);
880 881 882 883 884

	return TRUE;
}

static gboolean
885 886 887 888 889 890
drag_drop_cb (GtkWidget	        *widget,
	      GdkDragContext    *context,
	      gint               x,
	      gint               y,
	      guint              time,
	      Launcher          *launcher)
891 892 893
{
	GdkAtom ret_atom = 0;

894
	if (!panel_check_dnd_target_data (widget, context, NULL, &ret_atom))
895 896
		return FALSE;

897
	gtk_drag_get_data (widget, context, ret_atom, time);
898 899 900 901 902

	return TRUE;
}

static void  
903 904 905 906
drag_leave_cb (GtkWidget	*widget,
	       GdkDragContext   *context,
	       guint             time,
	       Launcher         *launcher)
907 908 909 910
{
	do_highlight (widget, FALSE);
}

911 912 913 914 915 916
void
panel_receive_dnd_data (PanelWidget      *panel,
			guint             info,
			int               pos,
			GtkSelectionData *selection_data,
			GdkDragContext   *context,
917
			guint             time_)
918 919 920
{
	switch (info) {
	case TARGET_URL:
921
		drop_urilist (panel, pos, (char *)selection_data->data);
922 923 924 925 926
		break;
	case TARGET_NETSCAPE_URL:
		drop_url (panel, pos, (char *)selection_data->data);
		break;
	case TARGET_COLOR:
927
		set_background_color (panel->toplevel, (guint16 *) selection_data->data);
928 929
		break;
	case TARGET_BGIMAGE:
930
		set_background_image_from_uri (panel->toplevel, (char *) selection_data->data);
931 932
		break;
	case TARGET_BACKGROUND_RESET:
933
		panel_profile_set_background_type (panel->toplevel, PANEL_BACK_NONE);
934 935 936 937 938 939 940 941 942
		break;
	case TARGET_DIRECTORY:
		drop_directory (panel, pos, (char *)selection_data->data);
		break;
	case TARGET_APPLET:
		if (!selection_data->data) {
			gtk_drag_finish (context, FALSE, FALSE, time_);
			return;
		}
943
		panel_applet_frame_create (panel->toplevel, pos, (char *) selection_data->data);
944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
		break;
	case TARGET_APPLET_INTERNAL:
		drop_internal_applet (panel, pos, (char *)selection_data->data,
				      context->action);
		break;
	case TARGET_ICON_INTERNAL:
		drop_internal_icon (panel, pos, (char *)selection_data->data,
				    context->action);
		break;
	default:
		gtk_drag_finish (context, FALSE, FALSE, time_);
		return;
	}

	gtk_drag_finish (context, TRUE, FALSE, time_);
}

961
static void
962
drag_data_recieved_cb (GtkWidget	*widget,
963 964 965 966 967 968
		       GdkDragContext   *context,
		       gint              x,
		       gint              y,
		       GtkSelectionData *selection_data,
		       guint             info,
		       guint             time)
969
{
970 971
	PanelWidget *panel_widget;
	int          pos;
972

973
	g_return_if_fail (PANEL_IS_TOPLEVEL (widget));
974

975 976 977
	/* we use this only to really find out the info, we already
	   know this is an ok drop site and the info that got passed
	   to us is bogus (it's always 0 in fact) */
978
	if (!panel_check_dnd_target_data (widget, context, &info, NULL)) {
979
		gtk_drag_finish (context, FALSE, FALSE, time);
980 981 982
		return;
	}

983
	panel_widget = panel_toplevel_get_panel_widget (PANEL_TOPLEVEL (widget));
984

985
	pos = panel_widget_get_cursorloc (panel_widget);
986
	
987
	/* 
988
	 * -1 passed to panel_applet_register will turn on 
989 990 991
	 * the insert_at_pos flag for panel_widget_add_full,
	 * which will not place it after the first applet.
	 */
992
	if(pos < 0)
993
		pos = -1;
994 995
	else if(pos > panel_widget->size)
		pos = panel_widget->size;
996

997
	panel_receive_dnd_data (
998
		panel_widget, info, pos, selection_data, context, time);
999
}
1000

1001 1002
static void
panel_widget_setup(PanelWidget *panel)
1003
{
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
	g_signal_connect (G_OBJECT(panel),
			  "applet_added",
			  G_CALLBACK(panel_applet_added),
			  NULL);
	g_signal_connect (G_OBJECT(panel),
			  "applet_removed",
			  G_CALLBACK(panel_applet_removed),
			  NULL);
	g_signal_connect (G_OBJECT(panel),
			  "applet_move",
			  G_CALLBACK(panel_applet_move),
			  NULL);
1016
#ifdef FIXME_FOR_NEW_TOPLEVEL
1017
	g_signal_connect (G_OBJECT (panel),
1018
			  "back_change",
1019
			  G_CALLBACK (panel_back_change),
1020
			  NULL);
1021
#endif
1022
	g_signal_connect (G_OBJECT (panel),
1023
			  "size_change",
1024
			  G_CALLBACK (panel_size_change),
1025
			  NULL);
1026 1027
}

1028
PanelData *
1029
panel_setup (PanelToplevel *toplevel)
Elliot Lee's avatar
Elliot Lee committed
1030
{
1031 1032
	PanelWidget *panel_widget;
	PanelData   *pd;
1033

1034
	g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
1035

1036
	panel_widget = panel_toplevel_get_panel_widget (toplevel);
1037

1038
	pd = g_new0 (PanelData,1);
1039
	pd->menu = NULL;
1040
	pd->panel = GTK_WIDGET (toplevel);
1041 1042
	pd->insertion_pos = -1;
	pd->deactivate_idle = 0;
1043

1044
	panel_list = g_slist_append (panel_list, pd);
1045
	
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071
	g_object_set_data (G_OBJECT (toplevel), "PanelData", pd);

	panel_widget_setup (panel_widget);

	g_signal_connect (toplevel, "drag_data_received",
			  G_CALLBACK (drag_data_recieved_cb), NULL);
	g_signal_connect (toplevel, "drag_motion",
			  G_CALLBACK (drag_motion_cb), NULL);
	g_signal_connect (toplevel, "drag_leave",
			  G_CALLBACK (drag_leave_cb), NULL);
	g_signal_connect (toplevel, "drag_drop",
			  G_CALLBACK (drag_drop_cb), NULL);

	gtk_drag_dest_set (GTK_WIDGET (toplevel), 0, NULL, 0, 0);

	g_signal_connect (toplevel, "key-press-event",
			  G_CALLBACK (panel_key_press_event), NULL);
	g_signal_connect (toplevel, "button-press-event",
			  G_CALLBACK (panel_button_press_event), NULL);
	g_signal_connect (toplevel, "popup-menu",
			  G_CALLBACK (panel_popup_menu_signal), NULL);

	g_signal_connect_swapped (toplevel, "notify::orientation",
				  G_CALLBACK (panel_orient_change), panel_widget);
 
	g_signal_connect (toplevel, "destroy", G_CALLBACK (panel_destroy), pd);
1072 1073

	return pd;
1074
}
1075

1076 1077
void
panel_register_window_icon (void)
1078
{
1079
	char *panel_icon;
1080

1081
	panel_icon = panel_pixmap_discovery ("gnome-panel.png", FALSE);
1082

1083 1084 1085
	if (panel_icon) {
		gnome_window_icon_set_default_from_file (panel_icon);
		g_free (panel_icon);
1086 1087 1088
	}
}

1089 1090 1091
GdkScreen *
panel_screen_from_panel_widget (PanelWidget *panel)
{
1092 1093
	g_return_val_if_fail (PANEL_IS_WIDGET (panel), NULL);
	g_return_val_if_fail (PANEL_IS_TOPLEVEL (panel->toplevel), NULL);
1094

1095
	return gtk_window_get_screen (GTK_WINDOW (panel->toplevel));
1096
}
1097

1098 1099
gboolean
panel_is_applet_right_stick (GtkWidget *applet)
1100
{
1101
	PanelWidget *panel_widget;
1102

1103 1104
	g_return_val_if_fail (GTK_IS_WIDGET (applet), FALSE);
	g_return_val_if_fail (PANEL_IS_WIDGET (applet->parent), FALSE);
1105

1106
	panel_widget = PANEL_WIDGET (applet->parent);
1107

1108
	if (!panel_toplevel_get_expand (panel_widget->toplevel))
1109
		return FALSE;
1110

1111
	return panel_widget_is_applet_stuck (panel_widget, applet);
1112
}
1113 1114

static void
1115
panel_delete_without_query (PanelToplevel *toplevel)
1116
{
1117
	PanelWidget *panel_widget;
1118

1119
	panel_widget = panel_toplevel_get_panel_widget (toplevel);
1120

1121 1122 1123 1124
	if (panel_toplevel_get_is_attached (toplevel) &&
	    panel_widget->master_widget) {
		AppletInfo *info;
		Drawer *drawer;
1125

1126 1127
		info = g_object_get_data (G_OBJECT (panel_widget->master_widget),
					  "applet_info");
1128

1129
		drawer = (Drawer *) info->data;
1130

1131 1132 1133
		panel_profile_delete_object (info);
	} else
		panel_profile_delete_toplevel (toplevel);
1134 1135 1136
} 

static void
1137 1138 1139
remove_panel_accept (GtkWidget     *dialog,
		     int            response,
		     PanelToplevel *toplevel)