panel.c 66.5 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

#include <libgnome/libgnome.h>
19
#include <libbonobo.h>
20
#include <libgnomevfs/gnome-vfs-uri.h>
21
#include <libgnomevfs/gnome-vfs-ops.h>
22
#include <libgnomevfs/gnome-vfs-mime.h>
23 24
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
#include <libgnomevfs/gnome-vfs-file-info.h>
25
#include <libgnomeui/gnome-window-icon.h>
26

Mark McLoughlin's avatar
Mark McLoughlin committed
27 28 29 30 31 32 33 34 35
#include "panel.h"

#include "applet.h"
#include "button-widget.h"
#include "distribution.h"
#include "drawer-widget.h"
#include "edge-widget.h"
#include "floating-widget.h"
#include "foobar-widget.h"
36
#include "gnome-run.h"
Mark McLoughlin's avatar
Mark McLoughlin committed
37 38 39 40 41 42
#include "launcher.h"
#include "logout.h"
#include "menu-fentry.h"
#include "menu-util.h"
#include "menu.h"
#include "panel-util.h"
43
#include "panel-config.h"
44 45
#include "panel-config-global.h"
#include "panel-gconf.h"
Mark McLoughlin's avatar
Mark McLoughlin committed
46 47 48
#include "session.h"
#include "status.h"
#include "swallow.h"
49
#include "panel-applet-frame.h"
50
#include "global-keys.h"
51 52

#define PANEL_EVENT_MASK (GDK_BUTTON_PRESS_MASK |		\
53 54 55
			   GDK_BUTTON_RELEASE_MASK |		\
			   GDK_POINTER_MOTION_MASK |		\
			   GDK_POINTER_MOTION_HINT_MASK)
56

57 58
#undef PANEL_SESSION_DEBUG

59
/*list of all panel widgets created*/
60
GSList *panel_list = NULL;
61

62
static gboolean panel_dragged = FALSE;
63
static guint panel_dragged_timeout = 0;
64
static gboolean panel_been_moved = FALSE;
65

George Lebl's avatar
George Lebl committed
66 67
/*the number of base panels (corner/snapped) out there, never let it
  go below 1*/
68 69
int base_panels = 0;

70 71
extern GSList *applets;

72
extern int applets_to_sync;
73
extern int panels_to_sync;
74

75
extern gboolean commie_mode;
76

77
extern GtkTooltips *panel_tooltips;
78

79 80
extern char *kde_menudir;

81 82 83 84 85



extern GlobalConfig global_config;

86
/*the types of stuff we accept*/
Owen Taylor's avatar
Owen Taylor committed
87 88 89

enum {
	TARGET_URL,
90
	TARGET_NETSCAPE_URL,
91 92
	TARGET_DIRECTORY,
	TARGET_COLOR,
93
	TARGET_APPLET,
94
	TARGET_APPLET_INTERNAL,
95
	TARGET_ICON_INTERNAL,
96 97
	TARGET_BGIMAGE,
	TARGET_BACKGROUND_RESET,
Owen Taylor's avatar
Owen Taylor committed
98 99
};

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
/* FIXME : Need to do some good error checking on all of these variables */

static GConfEnumStringPair panel_type_type_enum_map [] = {
	{ EDGE_PANEL,      "edge-panel" },
	{ DRAWER_PANEL,    "drawer-panel" },
	{ ALIGNED_PANEL,   "aligned-panel" },
	{ SLIDING_PANEL,   "sliding-panel" },
	{ FLOATING_PANEL,  "floating-panel" },
	{ FOOBAR_PANEL,	   "menu-panel" },
};

static GConfEnumStringPair background_type_enum_map [] = {
	{ PANEL_BACK_NONE,   "no-background" },
	{ PANEL_BACK_COLOR,  "color-background" },
	{ PANEL_BACK_PIXMAP, "pixmap-background" },
};

static GConfEnumStringPair panel_size_type_enum_map [] = {
	{ PANEL_SIZE_XX_SMALL, "panel-size-xx-small" },
	{ PANEL_SIZE_X_SMALL,  "panel-size-x-small" },
	{ PANEL_SIZE_SMALL,    "panel-size-small" },
	{ PANEL_SIZE_MEDIUM,   "panel-size-medium" },
	{ PANEL_SIZE_LARGE,    "panel-size-large" },
	{ PANEL_SIZE_X_LARGE,  "panel-size-x-large" },
	{ PANEL_SIZE_XX_LARGE, "panel-size-xx-large" },
};

static GConfEnumStringPair panel_edge_type_enum_map [] = {
	{ BORDER_TOP,    "panel-edge-top" },
	{ BORDER_RIGHT,  "panel-edge-right" },
	{ BORDER_BOTTOM, "panel-edge-bottom" },
	{ BORDER_LEFT,   "panel-edge-left" },
};

static GConfEnumStringPair panel_alignment_type_enum_map [] = {
	{ ALIGNED_LEFT,   "panel-alignment-left" },
	{ ALIGNED_CENTER, "panel-alignment-center" },
	{ ALIGNED_RIGHT,  "panel-alignment-right" },
};

static GConfEnumStringPair panel_anchor_type_enum_map [] = {
	{ SLIDING_ANCHOR_LEFT,  "panel-anchor-left" },
	{ SLIDING_ANCHOR_RIGHT, "panel-anchor-right" },
};

static GConfEnumStringPair panel_orient_type_enum_map [] = {
	{ PANEL_ORIENT_UP, "panel-orient-up" },
	{ PANEL_ORIENT_DOWN, "panel-orient-down" },
	{ PANEL_ORIENT_LEFT, "panel-orient-left" },
	{ PANEL_ORIENT_RIGHT, "panel-orient-right" },
};

static GConfEnumStringPair panel_orientation_type_enum_map [] = {
	{ GTK_ORIENTATION_HORIZONTAL, "panel-orientation-horizontal" },
	{ GTK_ORIENTATION_VERTICAL, "panel-orientation-vertical" },
};

157 158 159 160 161 162 163 164 165 166 167 168
static GConfEnumStringPair panel_speed_type_enum_map [] = {
	{ PANEL_SPEED_MEDIUM, "panel-speed-medium" },
	{ PANEL_SPEED_SLOW,   "panel-speed-slow" },
	{ PANEL_SPEED_FAST,   "panel-speed-fast" },
};

static GConfEnumStringPair panel_layer_type_enum_map [] = {
	{ LAYER_NORMAL, "panel-normal-layer" },
	{ LAYER_BELOW, "panel-below-layer" },
	{ LAYER_ABOVE, "panel-above-layer" },
};

169
static void
170 171
change_window_cursor(GdkWindow *window, GdkCursorType cursor_type)
{
172 173 174
	GdkCursor *cursor = gdk_cursor_new (cursor_type);
	gdk_window_set_cursor (window, cursor);
	gdk_cursor_unref (cursor);
175 176
}

177
static void
178
panel_realize (GtkWidget *widget, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
179
{
180
	change_window_cursor (widget->window, GDK_LEFT_PTR);
181
	
182
	if (BASEP_IS_WIDGET (widget))
183
		basep_widget_enable_buttons(BASEP_WIDGET(widget), TRUE);
184
	else if (FOOBAR_IS_WIDGET (widget))
185
		foobar_widget_update_winhints (FOOBAR_WIDGET(widget));
186

187 188
	/*FIXME: this seems to fix the panel size problems on startup
	  (from a report) but I don't think it's right*/
189
	gtk_widget_queue_resize (GTK_WIDGET (widget));
190 191
}

192
/*we call this recursively*/
193
static void orient_change_foreach(GtkWidget *w, gpointer data);
194

195
void
196 197
orientation_change (AppletInfo  *info,
		    PanelWidget *panel)
198
{
199

200
	switch (info->type) {
201
	case APPLET_BONOBO:
202
		panel_applet_frame_change_orient (PANEL_APPLET_FRAME (info->widget),
203
						  panel_widget_get_applet_orient (panel));
204
		break;
205 206
	case APPLET_MENU:
		set_menu_applet_orient ((Menu *)info->data,
207
					panel_widget_get_applet_orient (panel));
208 209 210 211 212 213
		break;
	case APPLET_DRAWER: {
		Drawer      *drawer = info->data;
		BasePWidget *basep = BASEP_WIDGET (drawer->drawer);

		set_drawer_applet_orient (drawer,
214
					  panel_widget_get_applet_orient (panel));
215 216 217 218
		gtk_widget_queue_resize (drawer->drawer);
		gtk_container_foreach (GTK_CONTAINER (basep->panel),
				       orient_change_foreach,
				       (gpointer)basep->panel);
219
		}
220 221
		break;
	case APPLET_SWALLOW: {
222 223
		Swallow *swallow = info->data;

224
		if (panel->orient == GTK_ORIENTATION_VERTICAL)
225 226
			set_swallow_applet_orient (swallow,
						   SWALLOW_VERTICAL);
227
		else
228 229 230 231 232
			set_swallow_applet_orient (swallow,
						   SWALLOW_HORIZONTAL);
		}
		break;
	case APPLET_STATUS: {
233
		StatusApplet *status = info->data;
234 235

		if (status->orient != panel->orient) {
236
			status->orient = panel->orient;
237
			status_applet_update (status);
238
		}
239 240 241 242
		}
		break;
	default:
		break;
243 244 245
	}
}

246
static void
247
orient_change_foreach(GtkWidget *w, gpointer data)
248
{
249
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
250
	PanelWidget *panel = data;
251
	
252
	orientation_change(info,panel);
253 254
}

255

256 257
static void
panel_orient_change(GtkWidget *widget,
258
		    GtkOrientation orient,
259 260
		    gpointer data)
{
261 262
	gtk_container_foreach(GTK_CONTAINER(widget),
			      orient_change_foreach,
263
			      widget);
264

265
	if (FLOATING_IS_WIDGET (PANEL_WIDGET (widget)->panel_parent))
266
		update_config_floating_orient (FLOATING_WIDGET (PANEL_WIDGET (widget)->panel_parent));
267

268
	panels_to_sync = TRUE;
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
}

static void
border_edge_change (BorderPos *border,
		    BorderEdge edge,
		    gpointer data)
{
	BasePWidget *basep = BASEP_WIDGET (data);
	PanelWidget *panel = PANEL_WIDGET (basep->panel);
	gtk_container_foreach (GTK_CONTAINER (panel),
			       orient_change_foreach,
			       panel);
	panels_to_sync = TRUE;
	update_config_edge (basep);
}

285 286 287 288
/*we call this recursively*/
static void size_change_foreach(GtkWidget *w, gpointer data);

void
Mark McLoughlin's avatar
Mark McLoughlin committed
289 290
size_change (AppletInfo  *info,
	     PanelWidget *panel)
291
{
Mark McLoughlin's avatar
Mark McLoughlin committed
292 293 294 295 296
	PanelSize size = panel->sz;
	
	switch (info->type) {
	case APPLET_BONOBO:
		panel_applet_frame_change_size (
297
			PANEL_APPLET_FRAME (info->widget), size);
Mark McLoughlin's avatar
Mark McLoughlin committed
298 299
		break;
	case APPLET_STATUS: {
300
		StatusApplet *status = info->data;
Mark McLoughlin's avatar
Mark McLoughlin committed
301 302 303 304 305 306 307 308

		status->size = size;

		status_applet_update (status);
		}
		break;
	default:
		break;
309 310 311 312 313 314
	}
}

static void
size_change_foreach(GtkWidget *w, gpointer data)
{
315
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
316 317 318 319 320 321 322 323
	PanelWidget *panel = data;
	
	size_change(info,panel);
}


static void
panel_size_change(GtkWidget *widget,
324
		  int sz,
325 326 327 328 329 330
		  gpointer data)
{
	gtk_container_foreach(GTK_CONTAINER(widget), size_change_foreach,
			      widget);
	panels_to_sync = TRUE;
	/*update the configuration box if it is displayed*/
331
	update_config_size (PANEL_WIDGET (widget)->panel_parent);
332 333
}

334
void
335
back_change (AppletInfo  *info,
Mark McLoughlin's avatar
Mark McLoughlin committed
336
	     PanelWidget *panel)
337
{
338 339 340
	if (info->type == APPLET_BONOBO)
		panel_applet_frame_change_background (
			PANEL_APPLET_FRAME (info->widget), panel->back_type);
Elliot Lee's avatar
Elliot Lee committed
341 342 343
}

static void
Mark McLoughlin's avatar
Mark McLoughlin committed
344 345
back_change_foreach (GtkWidget   *widget,
		     PanelWidget *panel)
Elliot Lee's avatar
Elliot Lee committed
346
{
Mark McLoughlin's avatar
Mark McLoughlin committed
347 348
	AppletInfo *info;

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

Mark McLoughlin's avatar
Mark McLoughlin committed
351
	back_change (info, panel);
Elliot Lee's avatar
Elliot Lee committed
352 353
}

354 355 356 357 358
static void
panel_back_change(GtkWidget *widget,
		  PanelBackType type,
		  char *pixmap,
		  GdkColor *color)
359
{
Mark McLoughlin's avatar
Mark McLoughlin committed
360 361 362
	gtk_container_foreach (GTK_CONTAINER (widget),
			       (GtkCallback) back_change_foreach,
			       widget);
363

364 365
	panels_to_sync = TRUE;
	/*update the configuration box if it is displayed*/
366
	update_config_back(PANEL_WIDGET(widget));
367 368
}

369
static void state_hide_foreach(GtkWidget *w, gpointer data);
370 371

static void
372
state_restore_foreach(GtkWidget *w, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
373
{
374
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
375 376
	
	if(info->type == APPLET_DRAWER) {
377
		Drawer *drawer = info->data;
378
		BasePWidget *basep = BASEP_WIDGET(drawer->drawer);
379 380 381 382 383 384 385 386 387

		DRAWER_POS (basep->pos)->temp_hidden = FALSE;
		gtk_widget_queue_resize (GTK_WIDGET (basep));

		gtk_container_foreach (GTK_CONTAINER (basep->panel),
				       (basep->state == BASEP_SHOWN)
				       ? state_restore_foreach
				       : state_hide_foreach,
				       NULL);
388
	}
Elliot Lee's avatar
Elliot Lee committed
389 390
}

391
static void
392
state_hide_foreach(GtkWidget *w, gpointer data)
393
{
394
	AppletInfo *info = g_object_get_data (G_OBJECT(w), "applet_info");
395 396
	if(info->type == APPLET_DRAWER) {
		Drawer *drawer = info->data;
397
		BasePWidget *basep = BASEP_WIDGET(drawer->drawer);
398
		GtkWidget *widget = GTK_WIDGET(basep);
399 400

		DRAWER_POS (basep->pos)->temp_hidden = TRUE;
401
		gtk_container_foreach(GTK_CONTAINER(basep->panel),
402 403
				      state_hide_foreach,
				      NULL);
404

405 406 407 408 409 410 411 412 413
		gtk_widget_queue_resize (widget);

		/* quickly hide the window from sight, the allocation
		   and all that will get updated in the main loop */
		if(widget->window) {
			gdk_window_move(widget->window,
					-widget->allocation.width - 1,
					-widget->allocation.height - 1);
		}
414
	}
415 416
}

417 418
static void
queue_resize_foreach(GtkWidget *w, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
419
{
420
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
421

422 423 424 425 426 427 428 429 430 431 432
	if(info->type == APPLET_DRAWER) {
		Drawer *drawer = info->data;
		BasePWidget *basep = BASEP_WIDGET(drawer->drawer);
		
		if(basep->state == BASEP_SHOWN) {
			gtk_widget_queue_resize(w);
			gtk_container_foreach(GTK_CONTAINER(basep->panel),
					       queue_resize_foreach,
					       NULL);
		}
	}
Elliot Lee's avatar
Elliot Lee committed
433
}
434

435 436
static void
basep_state_change(BasePWidget *basep,
437
		   BasePState old_state,
438
		   gpointer data)
439
{
440
	gtk_container_foreach (GTK_CONTAINER (basep->panel),
441
			       (basep->state == BASEP_SHOWN)
442 443
			       ? state_restore_foreach
			       : state_hide_foreach,
444
			       (gpointer)basep);
445 446
}

447 448 449 450
#ifdef FIXME
/* Is this even needed anymore - remove?
 */
static void
451 452 453 454 455 456
basep_type_change(BasePWidget *basep,
		  PanelType type,
		  gpointer data)
{
	update_config_type(basep);
	panels_to_sync = TRUE;
457 458
}
#endif
459

460 461
static void
panel_applet_added(GtkWidget *widget, GtkWidget *applet, gpointer data)
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
462
{
463
	AppletInfo *info = g_object_get_data (G_OBJECT (applet),
464
					       "applet_info");
465
	GtkWidget *panelw = PANEL_WIDGET(widget)->panel_parent;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
466
	
467 468
	/*
	 * on a real add the info will be NULL as the 
469
	 * only adding is done in panel_applet_register 
470 471 472 473
	 * and that doesn't add the info to the array until 
	 * after the add, so we can be sure this was 
	 * generated on a reparent.
	 */
474
	if((BASEP_IS_WIDGET(panelw) &&
475
	    !DRAWER_IS_WIDGET(panelw)) &&
476
	   info && info->type == APPLET_DRAWER) {
477
	        Drawer *drawer = info->data;
478 479 480 481 482
		BasePWidget *basep = BASEP_WIDGET(drawer->drawer);
		if(basep->state == BASEP_SHOWN ||
		   basep->state == BASEP_AUTO_HIDDEN) {
			BASEP_WIDGET(panelw)->drawers_open++;
			basep_widget_autoshow(BASEP_WIDGET(panelw));
483
		}
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
484
	}
485
	
486
	/*pop the panel up on addition*/
487
	if(BASEP_IS_WIDGET(panelw)) {
488
		basep_widget_autoshow(BASEP_WIDGET(panelw));
489
		/*try to pop down though if the mouse is out*/
490
		basep_widget_queue_autohide(BASEP_WIDGET(panelw));
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
491
	}
492

493 494 495
	orientation_change(info,PANEL_WIDGET(widget));
	size_change(info,PANEL_WIDGET(widget));
	back_change(info,PANEL_WIDGET(widget));
496 497

	/*we will need to save this applet's config now*/
498
	applets_to_sync = TRUE;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
499 500
}

501
static void
502
panel_applet_removed(GtkWidget *widget, GtkWidget *applet, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
503
{
504
	GtkWidget *parentw = PANEL_WIDGET(widget)->panel_parent;
505 506
	AppletInfo *info = g_object_get_data (G_OBJECT (applet),
					      "applet_info");
507 508

	/*we will need to save this applet's config now*/
509
	applets_to_sync = TRUE;
510
 
511 512
	if(info->type == APPLET_DRAWER) {
		Drawer *drawer = info->data;
513 514 515
		if((drawer->drawer) && (
			(BASEP_WIDGET(drawer->drawer)->state == BASEP_SHOWN) ||
			(BASEP_WIDGET(drawer->drawer)->state == BASEP_AUTO_HIDDEN))) {
516
			if(BASEP_IS_WIDGET(parentw)) {
517 518
				BASEP_WIDGET(parentw)->drawers_open--;
				basep_widget_queue_autohide(BASEP_WIDGET(parentw));
519 520 521 522 523
			}
		}
		/*it was a drawer so we need to save panels as well*/
		panels_to_sync = TRUE;
	}
524
}
Elliot Lee's avatar
Elliot Lee committed
525

526 527 528 529 530 531 532 533 534 535 536
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
537
static void
538
menu_deactivate(GtkWidget *w, PanelData *pd)
Elliot Lee's avatar
Elliot Lee committed
539
{
540
	pd->menu_age = 0;
541 542
	if (pd->deactivate_idle == 0)
		pd->deactivate_idle = g_idle_add (deactivate_idle, pd);
543
	if(BASEP_IS_WIDGET(pd->panel))
544
		BASEP_WIDGET(pd->panel)->autohide_inhibit = FALSE;
545 546
}

547 548
static void
move_panel_to_cursor(GtkWidget *w)
549
{
550 551
	int x,y;
	gdk_window_get_pointer(NULL,&x,&y,NULL);
552
	if(BASEP_IS_WIDGET(w))
553
		basep_widget_set_pos(BASEP_WIDGET(w),x,y);
554
}
555

556
static gboolean
557
panel_move_timeout(gpointer data)
558
{
559 560 561 562
	if(panel_dragged && panel_been_moved)
		move_panel_to_cursor(data);
	
	panel_been_moved = FALSE;
563
	panel_dragged_timeout = 0;
564

565
	return FALSE;
566 567
}

568
static void
569
panel_remove_applets (PanelWidget *panel)
570
{
571
	GList *l;
572

573 574 575
	for (l = panel->applet_list; l; l = l->next) {
		AppletData *ad = l->data;
		AppletInfo *info;
576

577 578
		info = g_object_get_data (G_OBJECT (ad->applet),
					  "applet_info");
579

580 581
		if (info->type == APPLET_BONOBO) {
			PanelAppletFrame *frame = info->data;
582

583 584 585
			panel_applet_frame_set_clean_remove
				(PANEL_APPLET_FRAME (frame), TRUE);
		} else if (info->type == APPLET_SWALLOW) {
586
			Swallow *swallow = info->data;
587

588 589 590 591 592
			swallow->clean_remove = TRUE;
		}
	}
}

593
static void
594
panel_destroy (GtkWidget *widget, gpointer data)
595
{
596
	PanelData *pd = g_object_get_data (G_OBJECT (widget), "PanelData");
597 598
	PanelWidget *panel = NULL;

599
	if (BASEP_IS_WIDGET (widget))
600
		panel = PANEL_WIDGET(BASEP_WIDGET(widget)->panel);
601
	else if (FOOBAR_IS_WIDGET (widget))
602
		panel = PANEL_WIDGET (FOOBAR_WIDGET (widget)->panel);
603

604
	panel_remove_applets (panel);
605
		
606 607
	kill_config_dialog(widget);

608
	if (DRAWER_IS_WIDGET(widget)) {
609 610 611 612
		GtkWidget *master_widget = panel->master_widget;

		if (master_widget != NULL) {
			AppletInfo *info =
613 614
				g_object_get_data (G_OBJECT (master_widget),
						   "applet_info");
615 616
			Drawer *drawer = info->data;
			drawer->drawer = NULL;
617
			panel_applet_clean (info);
618 619
			g_object_set_data (G_OBJECT (master_widget),
					   "applet_info", NULL);
620
		}
621
	} else if ((BASEP_IS_WIDGET(widget)
622 623
		    && !DRAWER_IS_WIDGET(widget))
		   || FOOBAR_IS_WIDGET (widget)) {
624 625 626
		/*this is a base panel and we just lost it*/
		base_panels--;
	}
627

628
	if (pd->menu != NULL)
629
		g_object_unref (G_OBJECT (pd->menu));
630
	pd->menu = NULL;
631

632 633
	pd->panel = NULL;

634 635 636 637
	if (pd->deactivate_idle != 0)
		g_source_remove (pd->deactivate_idle);
	pd->deactivate_idle = 0;

638 639
	g_object_set_data (G_OBJECT (widget), "PanelData", NULL);

640 641
	panel_list = g_slist_remove (panel_list, pd);
	g_free (pd);
642 643
}

644
static void
645
panel_applet_move(PanelWidget *panel, GtkWidget *widget, gpointer data)
646
{
647 648 649 650 651 652
	AppletInfo *info;

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

	g_return_if_fail (info);

653
	panel_applet_save_position (info, info->gconf_key, FALSE);
654 655
}

656
static void
657 658 659
panel_applet_about_to_die (GtkWidget *panel,
			   GtkWidget *widget,
			   gpointer   data)
660
{
661
	AppletInfo *info;
662

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

665
	g_return_if_fail (info);
666

667
	/*
668
	 * FIXME: we need to implement an applet died dialog box
669
	 */
670 671
}

672
static GtkWidget *
673
panel_menu_get (PanelWidget *panel, PanelData *pd)
674
{
675
	if (pd->menu != NULL)
676
		return pd->menu;
677
	
678 679
	pd->menu = g_object_ref (create_panel_context_menu (panel));
	gtk_object_sink (GTK_OBJECT (pd->menu));
680 681
	g_signal_connect (G_OBJECT (pd->menu), "deactivate",
			  G_CALLBACK (menu_deactivate), pd);
682
	return pd->menu;
683 684
}

685
GtkWidget *
686
make_popup_panel_menu (PanelWidget *panel)
687
{
688
	GtkWidget *panelw;
689 690 691
	PanelData *pd;
	GtkWidget *menu;

692
	if (!panel) {
693
		panelw = ((PanelData *)panel_list->data)->panel;
694
		if (BASEP_IS_WIDGET (panelw))
695
			panel = PANEL_WIDGET (BASEP_WIDGET (panelw)->panel);
696
		else if (FOOBAR_IS_WIDGET (panelw))
697
			panel = PANEL_WIDGET (FOOBAR_WIDGET (panelw)->panel);
698
	} else
699 700
		panelw = panel->panel_parent;

701
	pd = g_object_get_data (G_OBJECT (panelw), "PanelData");
702
	menu = panel_menu_get (panel, pd);
703
	g_object_set_data (G_OBJECT (menu), "menu_panel", panel);
704

705
	pd->menu_age = 0;
706
	return menu;
707
}
708 709 710 711 712 713 714

static gboolean
panel_initiate_move (GtkWidget *widget, guint32 event_time)
{
	PanelWidget *panel = NULL;
	BasePWidget *basep = NULL;

715
	if (BASEP_IS_WIDGET (widget)) {
716 717
		basep = BASEP_WIDGET (widget);
		panel = PANEL_WIDGET (basep->panel);
718
	} else if (FOOBAR_IS_WIDGET (widget)) {
719 720 721 722 723
		panel = PANEL_WIDGET (FOOBAR_WIDGET (widget)->panel);
	}

	/*this should probably be in snapped widget*/
	if(!panel_dragged &&
724 725
	   !DRAWER_IS_WIDGET (widget) &&
	   !FOOBAR_IS_WIDGET (widget)) {
726 727 728 729 730 731 732 733
		GdkCursor *cursor = gdk_cursor_new (GDK_FLEUR);
		gtk_grab_add(widget);
		gdk_pointer_grab (widget->window,
				  FALSE,
				  PANEL_EVENT_MASK,
				  NULL,
				  cursor,
				  event_time);
734
		gdk_cursor_unref (cursor);
735

736
		if (basep) {
737
			basep->autohide_inhibit = TRUE;
738 739
			basep_widget_init_offsets (basep);
		}
740 741 742

		panel_dragged = TRUE;
		return TRUE;
743
	} if(DRAWER_IS_WIDGET(widget) &&
744 745 746 747 748 749 750 751 752 753
	     !panel_applet_in_drag) {
		panel_widget_applet_drag_start (
						PANEL_WIDGET(panel->master_widget->parent),
						panel->master_widget,
						PW_DRAG_OFF_CURSOR);
		return TRUE;
	}

	return FALSE;
}
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779

static gboolean
panel_do_popup_menu (PanelWidget *panel, BasePWidget *basep, GtkWidget *widget, guint button, guint32 activate_time)
{
	if(!panel_applet_in_drag) {
		GtkWidget *menu;

		menu = make_popup_panel_menu (panel);
		if (basep) {
                        basep->autohide_inhibit = TRUE;
			basep_widget_autohide (basep);
		}

		gtk_menu_popup (GTK_MENU (menu),
                                NULL,
                                NULL,
                                panel_menu_position,
				widget,
				button,
                                activate_time);
		return TRUE;
	}
	return FALSE;
}

static gboolean
780
panel_popup_menu (GtkWidget *widget, gpointer data)
781 782 783 784
{
 	PanelWidget *panel = NULL;
	BasePWidget *basep = NULL;

785 786 787
	panel = PANEL_WIDGET (widget);
	if (BASEP_IS_WIDGET (data)) {
		basep = BASEP_WIDGET (data);
788 789 790 791
	}
	return panel_do_popup_menu (panel, basep, widget, 3, GDK_CURRENT_TIME);
}

792 793
static gboolean
pointer_in_widget (GtkWidget *widget, GdkEventButton *event)
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810
{
	int x, y;
	int wx, wy;
	int width, height;

	x = (int) event->x_root;
	y = (int) event->y_root;
	gdk_window_get_origin (widget->window, &wx, &wy);
	width = widget->allocation.width;
	height = widget->allocation.height;
	if ((x < wx || x >= wx + width) ||
            (y < wy || y >= wy + height))
		return FALSE;
	else
		return TRUE;
}

811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851
static void
queue_resize_button_widgets (GtkWidget *w, gpointer data)
{
	if (BUTTON_IS_WIDGET (w)) {
		gtk_widget_queue_resize (w);
	}
}

static gboolean
panel_end_move (GtkWidget *widget, GdkEventButton *bevent)
{
	if (panel_dragged &&
	    BASEP_IS_WIDGET (widget)) {
		BasePWidget *basep = BASEP_WIDGET (widget);
		basep_widget_set_pos (basep,
				      (gint16)bevent->x_root, 
				      (gint16)bevent->y_root);
		basep->autohide_inhibit = FALSE;
		basep_widget_queue_autohide (basep);

		gtk_grab_remove (widget);
		gdk_pointer_ungrab (bevent->time);
		panel_dragged = FALSE;
		if (panel_dragged_timeout != 0)
			g_source_remove (panel_dragged_timeout);
		panel_dragged_timeout = 0;
		panel_been_moved = FALSE;
		if (pointer_in_widget (basep->panel, bevent) &&
		    ! gtk_widget_is_focus (basep->panel))
			panel_widget_focus (PANEL_WIDGET (basep->panel));

		/* FIXME: why is this neccessary!!!!???? */
		gtk_container_foreach (GTK_CONTAINER (basep->panel),
				       queue_resize_button_widgets,
				       NULL);

		return TRUE;
	}
	return FALSE;
}

852
static gboolean
853
panel_event(GtkWidget *widget, GdkEvent *event)
854
{
855
	PanelData *pd;
856 857
	PanelWidget *panel = NULL;
	BasePWidget *basep = NULL;
858
	GdkEventButton *bevent;
859
	int x, y;
860

861
	if (BASEP_IS_WIDGET (widget)) {
862 863
		basep = BASEP_WIDGET (widget);
		panel = PANEL_WIDGET (basep->panel);
864
	} else if (FOOBAR_IS_WIDGET (widget)) {
865 866 867
		panel = PANEL_WIDGET (FOOBAR_WIDGET (widget)->panel);
	}

868 869 870
	switch (event->type) {
	case GDK_BUTTON_PRESS:
		bevent = (GdkEventButton *) event;
871 872 873 874
		if (panel_dragged) {
			return panel_end_move (widget, bevent);
		}
		switch (bevent->button) {
875
		case 3:
876 877 878 879 880 881 882 883 884
			/* Store the point where the popup menu was started to
			 * insert applets at that point */
			pd = g_object_get_data (G_OBJECT (widget), "PanelData");
			gtk_widget_get_pointer (GTK_WIDGET (panel), &x, &y);
			if (panel->orient == GTK_ORIENTATION_VERTICAL)
				pd->insertion_pos = y;
			else
				pd->insertion_pos = x;

885
			if (panel_do_popup_menu (panel, basep, widget, bevent->button, bevent->time))
886 887 888
				return TRUE;
			break;
		case 2:
889 890 891
			if ( ! commie_mode)
				return panel_initiate_move (widget,
							    bevent->time);
892
			break;
893
		default: break;
894
		}
895
		break;
896

897 898
	case GDK_BUTTON_RELEASE:
		bevent = (GdkEventButton *) event;
899 900
		if (panel_dragged) {
			return panel_end_move (widget, bevent);
901 902
		}
		break;
903 904
	case GDK_MOTION_NOTIFY:
		if (panel_dragged) {
905
			if (panel_dragged_timeout == 0) {
906
				panel_been_moved = FALSE;
907 908 909
				move_panel_to_cursor (widget);
				panel_dragged_timeout = g_timeout_add (30, panel_move_timeout, widget);
			} else {
910
				panel_been_moved = TRUE;
911
			}
912 913
		}
		break;
914

915 916 917
	default:
		break;
	}
918

919 920
	return FALSE;
}
921

922 923 924
static gboolean
panel_widget_event (GtkWidget *widget, GdkEvent *event, GtkWidget *panelw)
{
925 926 927
	if (commie_mode)
		return FALSE;

928 929 930
	if (event->type == GDK_BUTTON_PRESS) {
		GdkEventButton *bevent = (GdkEventButton *) event;

931
		if (bevent->button == 1 ||
932 933 934 935 936 937 938
		    bevent->button == 2) {
			if (panel_dragged) {
				return panel_end_move (widget, bevent);
			} else {
				return panel_initiate_move (panelw, bevent->time);
			}
		}
939 940 941 942 943 944
	}

	return FALSE;
}

static gboolean
945
panel_sub_event_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
946
{
947 948 949 950
	GdkEventButton *bevent;
	switch (event->type) {
		/*pass these to the parent!*/
		case GDK_BUTTON_PRESS:
951
	        case GDK_BUTTON_RELEASE:
952
	        case GDK_MOTION_NOTIFY:
953 954 955 956
			bevent = (GdkEventButton *) event;
			/*if the widget is a button we want to keep the
			  button 1 events*/
			if(!GTK_IS_BUTTON(widget) || bevent->button!=1)
957
				return gtk_widget_event(data, event);
958

959
			break;
960

961 962
		default:
			break;
963
	}
964

965
	return FALSE;
Arturo Espinosa's avatar
Arturo Espinosa committed
966 967
}

968
static void
969
drop_url(PanelWidget *panel, int pos, const char *url)
970
{
971 972 973 974 975
	char *p;

	g_return_if_fail (url != NULL);

	p = g_strdup_printf (_("Open URL: %s"), url);
976 977
	load_launcher_applet_from_info_url (url, p, url, "gnome-globe.png",
					    panel, pos, TRUE);
978
	g_free (p);
979 980 981
}

static void
982
drop_menu (PanelWidget *panel, int pos, const char *dir)
983
{
984
	int flags = MAIN_MENU_SYSTEM;
985
	DistributionType distribution = get_distribution_type ();
986

987 988 989
	/*guess distribution menus*/
	if(distribution != DISTRIBUTION_UNKNOWN)
		flags |= MAIN_MENU_DISTRIBUTION_SUB;
990
	/* Guess KDE menus */
991
	if (g_file_test (kde_menudir, G_FILE_TEST_IS_DIR))
992
		flags |= MAIN_MENU_KDE_SUB;
993 994
	/* FIXME: checkout gnome-vfs stuff for drop, this should be
	 * a uri */
Mark McLoughlin's avatar
Mark McLoughlin committed
995
	load_menu_applet (dir, FALSE /* main_menu */, flags, TRUE, FALSE, NULL, panel, pos, TRUE, NULL);
996 997
}

998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
static gboolean
uri_exists (const char *uri)
{
	gboolean ret;
	GnomeVFSURI *vfs_uri = gnome_vfs_uri_new (uri);
	ret = gnome_vfs_uri_exists (vfs_uri);
	gnome_vfs_uri_unref (vfs_uri);
	return ret;
}

static void
drop_nautilus_uri (PanelWidget *panel,
		   int pos,
		   const char *uri,
		   const char *icon)
{
	char *quoted = g_shell_quote (uri);
	char *exec = g_strdup_printf ("nautilus %s",
				      quoted);
	char *base;
	g_free (quoted);

	base = g_path_get_basename (uri);

	load_launcher_applet_from_info (base,
					uri,
					exec,
					icon,
					panel,
					pos,
					TRUE);
	g_free (exec);
	g_free (base);
}

1033 1034 1035 1036 1037
static void
drop_directory (PanelWidget *panel, int pos, const char *dir)
{
	char *tmp;

1038 1039 1040 1041
	/* not filename, but path, these are uris, not local
	 * files */
	tmp = g_build_path ("/", dir, ".directory", NULL);
	if (uri_exists (tmp)) {
1042 1043 1044 1045 1046 1047
		g_free (tmp);
		drop_menu (panel, pos, dir);
		return;
	}
	g_free (tmp);

1048 1049
	tmp = g_build_path ("/", dir, ".order", NULL);
	if (uri_exists (tmp)) {
1050 1051 1052 1053 1054 1055
		g_free (tmp);
		drop_menu (panel, pos, dir);
		return;
	}
	g_free (tmp);

1056
	if (panel_is_program_in_path ("nautilus")) {
1057
		/* nautilus */
1058
		drop_nautilus_uri (panel, pos, dir, "gnome-folder.png");
1059
	} else {
1060
		if (panel_is_program_in_path  ("gmc-client")) {
1061
			/* gmc */
1062
			char *name;
1063
			char *quoted = g_shell_quote (dir);
1064
			char *exec = g_strdup_printf ("gmc-client "
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1065
						      "--create-window=%s",
1066
						      quoted);
1067

1068
			g_free (quoted);
1069 1070 1071

			name = g_path_get_basename (dir);
			load_launcher_applet_from_info (name,
1072 1073 1074 1075 1076 1077
							dir,
							exec,
							"gnome-folder.png",
							panel,
							pos,
							TRUE);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
1078
			g_free (exec);
1079
			g_free (name);
1080 1081 1082 1083 1084 1085
		} else {
			drop_menu (panel, pos, dir);
		}
	}
}

1086
static void
1087 1088
drop_urilist (PanelWidget *panel, int pos, char *urilist,
	      gboolean background_drops)
1089 1090 1091
{
	GList *li, *files;

1092
	files = gnome_vfs_uri_list_parse (urilist);
1093

1094 1095 1096
	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);
1097
		const char *mimetype;
1098 1099
		char *basename;
		char *dirname;
1100
		char *filename;
1101
		GnomeVFSFileInfo *info;
1102

1103 1104 1105 1106 1107 1108 1109
		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) {
1110 1111 1112
			/* 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. */
1113
			drop_url (panel, pos, uri);
1114 1115 1116
			continue;
		}

1117 1118 1119 1120
		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 ();
1121

1122 1123 1124 1125
		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;
1126 1127
		}

1128 1129
		if (background_drops &&
		    mimetype != NULL &&
1130 1131 1132
		    strncmp(mimetype, "image", sizeof("image")-1) == 0 &&
		    /* FIXME: We should probably use a gnome-vfs function here instead. */
		    /* FIXME: probably port the whole panel background stuff to gnome-vfs */
1133
		    (filename = g_filename_from_uri (uri, NULL, NULL)) != NULL) {
1134
			panel_widget_set_back_pixmap (panel, filename);
1135 1136 1137 1138 1139 1140 1141 1142 1143
			g_free (filename);
		} else if (basename != NULL &&
			   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);
1144
		} else if (mimetype != NULL &&
1145 1146
			   (strcmp(mimetype, "application/x-gnome-app-info") == 0 ||
			    strcmp(mimetype, "application/x-kde-app-info") == 0)) {
1147
			Launcher *launcher;
1148
			
1149
			launcher = load_launcher_applet (uri, panel, pos, TRUE, NULL);
1150
			
1151 1152
			if (launcher != NULL)
				launcher_hoard (launcher);
1153 1154 1155 1156 1157 1158 1159 1160 1161
		} else if (info != NULL &&
			   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) &&
1162
			   (filename = g_filename_from_uri (uri, NULL, NULL)) != NULL) {
1163 1164
			/* executable and local, so add a launcher with
			 * it */
1165
			ask_about_launcher (filename, panel, pos, TRUE);
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
			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);
1183
		g_free (uri);
1184 1185
	}

1186
	gnome_vfs_uri_list_free (files);
1187 1188
}

1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
static void
drop_background_reset (PanelWidget *panel)
{
	panel_widget_change_params (panel,
				    panel->orient,
				    panel->sz,
				    PANEL_BACK_NONE,
				    panel->back_pixmap,
				    panel->fit_pixmap_bg,
				    panel->stretch_pixmap_bg,
				    panel->rotate_pixmap_bg,
				    &panel->back_color);
}

1203
static void
1204
drop_bgimage (PanelWidget *panel, const char *bgimage)
1205 1206 1207
{
	char *filename;

1208
	filename = g_filename_from_uri (bgimage, NULL, NULL);
1209
	if (filename != NULL) {