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

Mark McLoughlin's avatar
Mark McLoughlin committed
26 27 28 29 30 31 32 33 34
#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"
35
#include "gnome-run.h"
Mark McLoughlin's avatar
Mark McLoughlin committed
36 37 38 39 40 41
#include "launcher.h"
#include "logout.h"
#include "menu-fentry.h"
#include "menu-util.h"
#include "menu.h"
#include "panel-util.h"
42
#include "panel-config.h"
Mark McLoughlin's avatar
Mark McLoughlin committed
43 44 45
#include "session.h"
#include "status.h"
#include "swallow.h"
46
#include "panel-applet-frame.h"
47 48

#define PANEL_EVENT_MASK (GDK_BUTTON_PRESS_MASK |		\
49 50 51
			   GDK_BUTTON_RELEASE_MASK |		\
			   GDK_POINTER_MOTION_MASK |		\
			   GDK_POINTER_MOTION_HINT_MASK)
52

53
/*list of all panel widgets created*/
54
GSList *panel_list = NULL;
55

56
static gboolean panel_dragged = FALSE;
57
static int panel_dragged_timeout = -1;
58
static gboolean panel_been_moved = FALSE;
59

George Lebl's avatar
George Lebl committed
60 61
/*the number of base panels (corner/snapped) out there, never let it
  go below 1*/
62 63
int base_panels = 0;

64 65
extern GSList *applets;

66
extern int applets_to_sync;
67
extern int panels_to_sync;
68

69
extern gboolean commie_mode;
70

71
extern GtkTooltips *panel_tooltips;
72

73 74
extern char *kde_menudir;

75
/*the types of stuff we accept*/
Owen Taylor's avatar
Owen Taylor committed
76 77 78

enum {
	TARGET_URL,
79
	TARGET_NETSCAPE_URL,
80 81
	TARGET_DIRECTORY,
	TARGET_COLOR,
82
	TARGET_APPLET,
83
	TARGET_APPLET_INTERNAL,
84
	TARGET_ICON_INTERNAL,
85 86
	TARGET_BGIMAGE,
	TARGET_BACKGROUND_RESET,
Owen Taylor's avatar
Owen Taylor committed
87 88
};

89
static void
90 91
change_window_cursor(GdkWindow *window, GdkCursorType cursor_type)
{
92 93 94
	GdkCursor *cursor = gdk_cursor_new (cursor_type);
	gdk_window_set_cursor (window, cursor);
	gdk_cursor_unref (cursor);
95 96
}

97
static void
98
panel_realize (GtkWidget *widget, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
99
{
100
	change_window_cursor (widget->window, GDK_LEFT_PTR);
101
	
102
	if (BASEP_IS_WIDGET (widget))
103
		basep_widget_enable_buttons(BASEP_WIDGET(widget));
104
	else if (FOOBAR_IS_WIDGET (widget))
105
		foobar_widget_update_winhints (FOOBAR_WIDGET(widget));
106

107 108
	/*FIXME: this seems to fix the panel size problems on startup
	  (from a report) but I don't think it's right*/
109
	gtk_widget_queue_resize (GTK_WIDGET (widget));
110 111
}

112
PanelOrient
113 114
get_applet_orient (PanelWidget *panel)
{
115
	GtkWidget *panelw;
116
	g_return_val_if_fail(panel,PANEL_ORIENT_UP);
117
	g_return_val_if_fail(PANEL_IS_WIDGET(panel),PANEL_ORIENT_UP);
118
	g_return_val_if_fail(panel->panel_parent,PANEL_ORIENT_UP);
119
	panelw = panel->panel_parent;
120

121
	if (BASEP_IS_WIDGET(panelw))
122 123
		return basep_widget_get_applet_orient (BASEP_WIDGET(panelw));
	else
124
		return PANEL_ORIENT_DOWN;
125 126
}

127
/*we call this recursively*/
128
static void orient_change_foreach(GtkWidget *w, gpointer data);
129

130
void
131 132
orientation_change (AppletInfo  *info,
		    PanelWidget *panel)
133
{
134

135
	switch (info->type) {
136 137 138 139
	case APPLET_BONOBO:
		panel_applet_frame_change_orient ((PanelAppletFrame *) info->data,
						  get_applet_orient (panel));
		break;
140 141 142 143 144 145 146 147 148 149 150 151 152 153
	case APPLET_MENU:
		set_menu_applet_orient ((Menu *)info->data,
					get_applet_orient (panel));
		break;
	case APPLET_DRAWER: {
		Drawer      *drawer = info->data;
		BasePWidget *basep = BASEP_WIDGET (drawer->drawer);

		set_drawer_applet_orient (drawer,
					  get_applet_orient (panel));
		gtk_widget_queue_resize (drawer->drawer);
		gtk_container_foreach (GTK_CONTAINER (basep->panel),
				       orient_change_foreach,
				       (gpointer)basep->panel);
154
		}
155 156
		break;
	case APPLET_SWALLOW: {
157 158
		Swallow *swallow = info->data;

159
		if (panel->orient == GTK_ORIENTATION_VERTICAL)
160 161
			set_swallow_applet_orient (swallow,
						   SWALLOW_VERTICAL);
162
		else
163 164 165 166 167
			set_swallow_applet_orient (swallow,
						   SWALLOW_HORIZONTAL);
		}
		break;
	case APPLET_STATUS: {
168
		StatusApplet *status = info->data;
169 170

		if (status->orient != panel->orient) {
171
			status->orient = panel->orient;
172
			status_applet_update (status);
173
		}
174 175 176 177
		}
		break;
	default:
		break;
178 179 180
	}
}

181
static void
182
orient_change_foreach(GtkWidget *w, gpointer data)
183
{
184
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
185
	PanelWidget *panel = data;
186
	
187
	orientation_change(info,panel);
188 189
}

190

191 192
static void
panel_orient_change(GtkWidget *widget,
193
		    GtkOrientation orient,
194 195
		    gpointer data)
{
196 197
	gtk_container_foreach(GTK_CONTAINER(widget),
			      orient_change_foreach,
198
			      widget);
199

200
	if (FLOATING_IS_WIDGET (PANEL_WIDGET (widget)->panel_parent))
201
		update_config_floating_orient (FLOATING_WIDGET (PANEL_WIDGET (widget)->panel_parent));
202

203
	panels_to_sync = TRUE;
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
}

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);
}

220 221 222 223
/*we call this recursively*/
static void size_change_foreach(GtkWidget *w, gpointer data);

void
Mark McLoughlin's avatar
Mark McLoughlin committed
224 225
size_change (AppletInfo  *info,
	     PanelWidget *panel)
226
{
Mark McLoughlin's avatar
Mark McLoughlin committed
227 228 229 230 231 232 233 234
	PanelSize size = panel->sz;
	
	switch (info->type) {
	case APPLET_BONOBO:
		panel_applet_frame_change_size (
			PANEL_APPLET_FRAME (info->data), size);
		break;
	case APPLET_STATUS: {
235
		StatusApplet *status = info->data;
Mark McLoughlin's avatar
Mark McLoughlin committed
236 237 238 239 240 241 242 243

		status->size = size;

		status_applet_update (status);
		}
		break;
	default:
		break;
244 245 246 247 248 249
	}
}

static void
size_change_foreach(GtkWidget *w, gpointer data)
{
250
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
251 252 253 254 255 256 257 258
	PanelWidget *panel = data;
	
	size_change(info,panel);
}


static void
panel_size_change(GtkWidget *widget,
259
		  int sz,
260 261 262 263 264 265
		  gpointer data)
{
	gtk_container_foreach(GTK_CONTAINER(widget), size_change_foreach,
			      widget);
	panels_to_sync = TRUE;
	/*update the configuration box if it is displayed*/
266
	update_config_size (PANEL_WIDGET (widget)->panel_parent);
267 268
}

269
void
270
back_change (AppletInfo  *info,
Mark McLoughlin's avatar
Mark McLoughlin committed
271
	     PanelWidget *panel)
272
{
273
	if (info->type == APPLET_BONOBO) {
Mark McLoughlin's avatar
Mark McLoughlin committed
274 275 276 277 278 279 280 281
		PanelAppletFrame *frame = PANEL_APPLET_FRAME (info->data);

		switch (panel->back_type) {
		case PANEL_BACK_PIXMAP:
			panel_applet_frame_change_background_pixmap (frame,
								     panel->back_pixmap);
			break;
		case PANEL_BACK_COLOR:
282 283 284 285
			panel_applet_frame_change_background_color (frame,
								    panel->back_color.red,
								    panel->back_color.green,
								    panel->back_color.blue);
Mark McLoughlin's avatar
Mark McLoughlin committed
286 287 288 289 290 291 292 293 294
			break;
		case PANEL_BACK_NONE:
			panel_applet_frame_clear_background (frame);
			break;
		default:
			g_assert_not_reached ();
			break;
		}
	}
Elliot Lee's avatar
Elliot Lee committed
295 296 297
}

static void
Mark McLoughlin's avatar
Mark McLoughlin committed
298 299
back_change_foreach (GtkWidget   *widget,
		     PanelWidget *panel)
Elliot Lee's avatar
Elliot Lee committed
300
{
Mark McLoughlin's avatar
Mark McLoughlin committed
301 302
	AppletInfo *info;

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

Mark McLoughlin's avatar
Mark McLoughlin committed
305
	back_change (info, panel);
Elliot Lee's avatar
Elliot Lee committed
306 307
}

308 309 310 311 312
static void
panel_back_change(GtkWidget *widget,
		  PanelBackType type,
		  char *pixmap,
		  GdkColor *color)
313
{
Mark McLoughlin's avatar
Mark McLoughlin committed
314 315 316
	gtk_container_foreach (GTK_CONTAINER (widget),
			       (GtkCallback) back_change_foreach,
			       widget);
317

318 319
	panels_to_sync = TRUE;
	/*update the configuration box if it is displayed*/
320
	update_config_back(PANEL_WIDGET(widget));
321 322
}

323
static void state_hide_foreach(GtkWidget *w, gpointer data);
324 325

static void
326
state_restore_foreach(GtkWidget *w, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
327
{
328
	AppletInfo *info = g_object_get_data (G_OBJECT (w), "applet_info");
329 330
	
	if(info->type == APPLET_DRAWER) {
331
		Drawer *drawer = info->data;
332
		BasePWidget *basep = BASEP_WIDGET(drawer->drawer);
333 334 335 336 337 338 339 340 341

		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);
342
	}
Elliot Lee's avatar
Elliot Lee committed
343 344
}

345
static void
346
state_hide_foreach(GtkWidget *w, gpointer data)
347
{
348
	AppletInfo *info = g_object_get_data (G_OBJECT(w), "applet_info");
349 350
	if(info->type == APPLET_DRAWER) {
		Drawer *drawer = info->data;
351
		BasePWidget *basep = BASEP_WIDGET(drawer->drawer);
352
		GtkWidget *widget = GTK_WIDGET(basep);
353 354

		DRAWER_POS (basep->pos)->temp_hidden = TRUE;
355
		gtk_container_foreach(GTK_CONTAINER(basep->panel),
356 357
				      state_hide_foreach,
				      NULL);
358

359 360 361 362 363 364 365 366 367
		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);
		}
368
	}
369 370
}

371 372
static void
queue_resize_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 377 378 379 380 381 382 383 384 385 386
	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
387
}
388

389 390
static void
basep_state_change(BasePWidget *basep,
391 392
		   BasePState state,
		   gpointer data)
393
{
394 395 396 397
	gtk_container_foreach (GTK_CONTAINER (basep->panel),
			       (state == BASEP_SHOWN)
			       ? state_restore_foreach
			       : state_hide_foreach,
398
			       (gpointer)basep);
399 400
}

401 402 403 404 405 406 407 408 409
/*static void
basep_type_change(BasePWidget *basep,
		  PanelType type,
		  gpointer data)
{
	update_config_type(basep);
	panels_to_sync = TRUE;
}*/

410 411
static void
panel_applet_added(GtkWidget *widget, GtkWidget *applet, gpointer data)
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
412
{
413
	AppletInfo *info = g_object_get_data (G_OBJECT (applet),
414
					       "applet_info");
415
	GtkWidget *panelw = PANEL_WIDGET(widget)->panel_parent;
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
416
	
417 418
	/*
	 * on a real add the info will be NULL as the 
419
	 * only adding is done in panel_applet_register 
420 421 422 423
	 * 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.
	 */
424
	if((BASEP_IS_WIDGET(panelw) &&
425
	    !DRAWER_IS_WIDGET(panelw)) &&
426
	   info && info->type == APPLET_DRAWER) {
427
	        Drawer *drawer = info->data;
428 429 430 431 432
		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));
433
		}
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
434
	}
435
	
436
	/*pop the panel up on addition*/
437
	if(BASEP_IS_WIDGET(panelw)) {
438
		basep_widget_autoshow(BASEP_WIDGET(panelw));
439
		/*try to pop down though if the mouse is out*/
440
		basep_widget_queue_autohide(BASEP_WIDGET(panelw));
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
441
	}
442

443 444 445
	orientation_change(info,PANEL_WIDGET(widget));
	size_change(info,PANEL_WIDGET(widget));
	back_change(info,PANEL_WIDGET(widget));
446 447

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

451
static void
452
panel_applet_removed(GtkWidget *widget, GtkWidget *applet, gpointer data)
Elliot Lee's avatar
Elliot Lee committed
453
{
454
	GtkWidget *parentw = PANEL_WIDGET(widget)->panel_parent;
455 456
	AppletInfo *info = g_object_get_data (G_OBJECT (applet),
					      "applet_info");
457 458

	/*we will need to save this applet's config now*/
459
	applets_to_sync = TRUE;
460 461 462

	if(info->type == APPLET_DRAWER) {
		Drawer *drawer = info->data;
463 464 465
		if((drawer->drawer) && (
			(BASEP_WIDGET(drawer->drawer)->state == BASEP_SHOWN) ||
			(BASEP_WIDGET(drawer->drawer)->state == BASEP_AUTO_HIDDEN))) {
466
			if(BASEP_IS_WIDGET(parentw)) {
467 468
				BASEP_WIDGET(parentw)->drawers_open--;
				basep_widget_queue_autohide(BASEP_WIDGET(parentw));
469 470 471 472 473
			}
		}
		/*it was a drawer so we need to save panels as well*/
		panels_to_sync = TRUE;
	}
474
}
Elliot Lee's avatar
Elliot Lee committed
475 476

static void
477
menu_deactivate(GtkWidget *w, PanelData *pd)
Elliot Lee's avatar
Elliot Lee committed
478
{
479
	pd->menu_age = 0;
480
	if(BASEP_IS_WIDGET(pd->panel))
481
		BASEP_WIDGET(pd->panel)->autohide_inhibit = FALSE;
482 483
}

484 485
static void
move_panel_to_cursor(GtkWidget *w)
486
{
487 488
	int x,y;
	gdk_window_get_pointer(NULL,&x,&y,NULL);
489
	if(BASEP_IS_WIDGET(w))
490
		basep_widget_set_pos(BASEP_WIDGET(w),x,y);
491
}
492

493
static gboolean
494
panel_move_timeout(gpointer data)
495
{
496 497 498 499 500
	if(panel_dragged && panel_been_moved)
		move_panel_to_cursor(data);
	
	panel_been_moved = FALSE;
	panel_dragged_timeout = -1;
501

502
	return FALSE;
503 504
}

505
static void
506
panel_remove_applets (PanelWidget *panel)
507
{
508
	GList *l;
509

510 511 512
	for (l = panel->applet_list; l; l = l->next) {
		AppletData *ad = l->data;
		AppletInfo *info;
513

514 515
		info = g_object_get_data (G_OBJECT (ad->applet),
					  "applet_info");
516

517 518 519
		switch (info->type) {
		case APPLET_BONOBO:
			panel_applet_frame_save_position (
520
				PANEL_APPLET_FRAME (info->data));
521 522
			break;
		case APPLET_SWALLOW: {
523
			Swallow *swallow = info->data;
524

525
			swallow->clean_remove = TRUE;
526 527 528 529
			}
			break;
		default:
			break;
530 531
		}
	}
532

533
	gnome_config_sync ();
534 535
}

536
static void
537
panel_destroy (GtkWidget *widget, gpointer data)
538
{
539
	PanelData *pd = g_object_get_data (G_OBJECT (widget), "PanelData");
540 541
	PanelWidget *panel = NULL;

542
	if (BASEP_IS_WIDGET (widget))
543
		panel = PANEL_WIDGET(BASEP_WIDGET(widget)->panel);
544
	else if (FOOBAR_IS_WIDGET (widget))
545
		panel = PANEL_WIDGET (FOOBAR_WIDGET (widget)->panel);
546

547
	panel_remove_applets (panel);
548
		
549 550
	kill_config_dialog(widget);

551
	if (DRAWER_IS_WIDGET(widget)) {
552 553 554 555
		GtkWidget *master_widget = panel->master_widget;

		if (master_widget != NULL) {
			AppletInfo *info =
556 557
				g_object_get_data (G_OBJECT (master_widget),
						   "applet_info");
558 559
			Drawer *drawer = info->data;
			drawer->drawer = NULL;
560
			panel_applet_clean (info);
561 562
			g_object_set_data (G_OBJECT (master_widget),
					   "applet_info", NULL);
563
		}
564
	} else if ((BASEP_IS_WIDGET(widget)
565 566
		    && !DRAWER_IS_WIDGET(widget))
		   || FOOBAR_IS_WIDGET (widget)) {
567 568 569
		/*this is a base panel and we just lost it*/
		base_panels--;
	}
570

571 572
	if (pd->menu != NULL)
		gtk_widget_unref (pd->menu);
573
	pd->menu = NULL;
574

575 576
	pd->panel = NULL;

577 578
	panel_list = g_slist_remove (panel_list, pd);
	g_free (pd);
579 580
}

581
static void
582
panel_applet_move(PanelWidget *panel, GtkWidget *widget, gpointer data)
583
{
584
	applets_to_sync = TRUE;
585 586
}

587
static void
588 589 590
panel_applet_about_to_die (GtkWidget *panel,
			   GtkWidget *widget,
			   gpointer   data)
591
{
592
	AppletInfo *info;
593

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

596
	g_return_if_fail (info);
597

598
	/*
599
	 * FIXME: we need to implement an applet died dialog box
600
	 */
601 602
}

603
static GtkWidget *
604
panel_menu_get (PanelWidget *panel, PanelData *pd)
605
{
606
	if (pd->menu != NULL)
607
		return pd->menu;
608
	
609
	pd->menu = create_panel_root_menu (panel, TRUE);
610 611
	g_signal_connect (G_OBJECT (pd->menu), "deactivate",
			  G_CALLBACK (menu_deactivate), pd);
612
	return pd->menu;
613 614
}

615
GtkWidget *
616
make_popup_panel_menu (PanelWidget *panel)
617
{
618
	GtkWidget *panelw;
619 620 621
	PanelData *pd;
	GtkWidget *menu;

622
	if (!panel) {
623
		panelw = ((PanelData *)panel_list->data)->panel;
624
		if (BASEP_IS_WIDGET (panelw))
625
			panel = PANEL_WIDGET (BASEP_WIDGET (panelw)->panel);
626
		else if (FOOBAR_IS_WIDGET (panelw))
627
			panel = PANEL_WIDGET (FOOBAR_WIDGET (panelw)->panel);
628
	} else
629 630
		panelw = panel->panel_parent;

631
	pd = g_object_get_data (G_OBJECT (panelw), "PanelData");
632
	menu = panel_menu_get (panel, pd);
633
	g_object_set_data (G_OBJECT (menu), "menu_panel", panel);
634

635
	pd->menu_age = 0;
636
	return menu;
637
}
638 639 640 641 642 643 644

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

645
	if (BASEP_IS_WIDGET (widget)) {
646 647
		basep = BASEP_WIDGET (widget);
		panel = PANEL_WIDGET (basep->panel);
648
	} else if (FOOBAR_IS_WIDGET (widget)) {
649 650 651 652 653
		panel = PANEL_WIDGET (FOOBAR_WIDGET (widget)->panel);
	}

	/*this should probably be in snapped widget*/
	if(!panel_dragged &&
654 655
	   !DRAWER_IS_WIDGET (widget) &&
	   !FOOBAR_IS_WIDGET (widget)) {
656 657 658 659 660 661 662 663
		GdkCursor *cursor = gdk_cursor_new (GDK_FLEUR);
		gtk_grab_add(widget);
		gdk_pointer_grab (widget->window,
				  FALSE,
				  PANEL_EVENT_MASK,
				  NULL,
				  cursor,
				  event_time);
664
		gdk_cursor_unref (cursor);
665

666
		if (basep) {
667
			basep->autohide_inhibit = TRUE;
668 669
			basep_widget_init_offsets (basep);
		}
670 671 672

		panel_dragged = TRUE;
		return TRUE;
673
	} if(DRAWER_IS_WIDGET(widget) &&
674 675 676 677 678 679 680 681 682 683
	     !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;
}
684
	
685
static gboolean
686
panel_event(GtkWidget *widget, GdkEvent *event, PanelData *pd)
687
{
688 689
	PanelWidget *panel = NULL;
	BasePWidget *basep = NULL;
690
	GdkEventButton *bevent;
691

692
	if (BASEP_IS_WIDGET (widget)) {
693 694
		basep = BASEP_WIDGET (widget);
		panel = PANEL_WIDGET (basep->panel);
695
	} else if (FOOBAR_IS_WIDGET (widget)) {
696 697 698
		panel = PANEL_WIDGET (FOOBAR_WIDGET (widget)->panel);
	}

699 700 701 702
	switch (event->type) {
	case GDK_BUTTON_PRESS:
		bevent = (GdkEventButton *) event;
		switch(bevent->button) {
703
		case 3:
704
			if(!panel_applet_in_drag) {
705
				GtkWidget *menu;
706 707 708 709 710 711 712

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

713 714 715 716 717 718 719 720
				gtk_menu_popup (GTK_MENU (menu),
						NULL,
						NULL, 
						panel_menu_position,
						widget,
						bevent->button,
						bevent->time);

721 722 723 724
				return TRUE;
			}
			break;
		case 2:
725 726 727
			if ( ! commie_mode)
				return panel_initiate_move (widget,
							    bevent->time);
728
			break;
729
		default: break;
730
		}
731
		break;
732

733 734 735
	case GDK_BUTTON_RELEASE:
		bevent = (GdkEventButton *) event;
		if(panel_dragged) {
736 737
			if (!basep)
				return TRUE;
738 739 740 741 742 743
			basep_widget_set_pos(basep,
					     (gint16)bevent->x_root, 
					     (gint16)bevent->y_root);
			basep->autohide_inhibit = FALSE;
			basep_widget_queue_autohide(BASEP_WIDGET(widget));

744 745
			gdk_pointer_ungrab(bevent->time);
			gtk_grab_remove(widget);
746 747 748
			panel_dragged = FALSE;
			panel_dragged_timeout = -1;
			panel_been_moved = FALSE;
749 750
			return TRUE;
		}
751

752
		break;
753 754 755 756 757
	case GDK_MOTION_NOTIFY:
		if (panel_dragged) {
			if(panel_dragged_timeout==-1) {
				panel_been_moved = FALSE;
				move_panel_to_cursor(widget);
758
				panel_dragged_timeout = gtk_timeout_add (30,panel_move_timeout,widget);
759 760 761 762
			} else
				panel_been_moved = TRUE;
		}
		break;
763

764 765 766
	default:
		break;
	}
767

768 769
	return FALSE;
}
770

771 772 773 774 775 776
static gboolean
panel_widget_event (GtkWidget *widget, GdkEvent *event, GtkWidget *panelw)
{
	if (event->type == GDK_BUTTON_PRESS) {
		GdkEventButton *bevent = (GdkEventButton *) event;

777 778 779
		if (bevent->button == 1 ||
		    bevent->button == 2)
			return panel_initiate_move (panelw, bevent->time);
780 781 782 783 784 785
	}

	return FALSE;
}

static gboolean
786
panel_sub_event_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
787
{
788 789 790 791
	GdkEventButton *bevent;
	switch (event->type) {
		/*pass these to the parent!*/
		case GDK_BUTTON_PRESS:
792
	        case GDK_BUTTON_RELEASE:
793
	        case GDK_MOTION_NOTIFY:
794 795 796 797
			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)
798
				return gtk_widget_event(data, event);
799

800
			break;
801

802 803
		default:
			break;
804
	}
805

806
	return FALSE;
Arturo Espinosa's avatar
Arturo Espinosa committed
807 808
}

809 810 811 812
static gchar *
extract_filename (const gchar* uri)
{
	/* file uri with a hostname */
813 814 815
	if (strncmp (uri, "file://", strlen ("file://")) == 0) {
		char *hostname = g_strdup (&uri[strlen("file://")]);
		char *p = strchr (hostname, '/');
816 817 818
		char *path;
		char localhostname[1024];
		/* if we can't find the '/' this uri is bad */
819 820
		if(p == NULL) {
			g_free (hostname);
821 822 823
			return NULL;
		}
		/* if no hostname */
824
		if(p == hostname)
825 826
			return hostname;

827
		path = g_strdup (p);
828 829 830
		*p = '\0';

		/* if really local */
831 832
		if (g_ascii_strcasecmp (hostname, "localhost") == 0 ||
		    g_ascii_strcasecmp (hostname, "localhost.localdomain") == 0) {
833
			g_free (hostname);
834 835 836 837
			return path;
		}

		/* ok get the hostname */
838 839 840
		if (gethostname (localhostname,
				 sizeof (localhostname)) < 0) {
			strcpy (localhostname, "");
841 842 843
		}

		/* if really local */
844
		if (localhostname[0] &&
845
		    g_ascii_strcasecmp (hostname, localhostname) == 0) {
846
			g_free (hostname);
847 848 849
			return path;
		}
		
850 851
		g_free (hostname);
		g_free (path);
852 853 854 855 856 857 858 859 860 861 862 863 864 865
		return NULL;

	/* if the file doesn't have the //, we take it containing 
	   a local path */
	} else if (strncmp(uri, "file:", strlen("file:"))==0) {
		const char *path = &uri[strlen("file:")];
		/* if empty bad */
		if(!*path) return NULL;
		return g_strdup(path);
	}
	return NULL;
}

static void
866
drop_url(PanelWidget *panel, int pos, const char *url)
867
{
868 869 870 871 872
	char *p;

	g_return_if_fail (url != NULL);

	p = g_strdup_printf (_("Open URL: %s"), url);
873 874
	load_launcher_applet_from_info_url (url, p, url, "gnome-globe.png",
					    panel, pos, TRUE);
875
	g_free (p);
876 877 878
}

static void
879
drop_menu (PanelWidget *panel, int pos, const char *dir)
880
{
881
	int flags = MAIN_MENU_SYSTEM;
882
	DistributionType distribution = get_distribution_type ();
883

884 885 886
	/*guess distribution menus*/
	if(distribution != DISTRIBUTION_UNKNOWN)
		flags |= MAIN_MENU_DISTRIBUTION_SUB;
887
	/* Guess KDE menus */
888
	if (g_file_test (kde_menudir, G_FILE_TEST_IS_DIR))
889
		flags |= MAIN_MENU_KDE_SUB;
890 891 892
	/* FIXME: checkout gnome-vfs stuff for drop, this should be
	 * a uri */
	load_menu_applet (dir, FALSE /* main_menu */, flags, TRUE, FALSE, NULL, panel, pos, TRUE);
893 894
}

895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929
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);
}

930 931 932 933 934
static void
drop_directory (PanelWidget *panel, int pos, const char *dir)
{
	char *tmp;

935 936 937 938
	/* not filename, but path, these are uris, not local
	 * files */
	tmp = g_build_path ("/", dir, ".directory", NULL);
	if (uri_exists (tmp)) {
939 940 941 942 943 944
		g_free (tmp);
		drop_menu (panel, pos, dir);
		return;
	}
	g_free (tmp);

945 946
	tmp = g_build_path ("/", dir, ".order", NULL);
	if (uri_exists (tmp)) {
947 948 949 950 951 952
		g_free (tmp);
		drop_menu (panel, pos, dir);
		return;
	}
	g_free (tmp);

953
	if (panel_is_program_in_path ("nautilus")) {
954
		/* nautilus */
955
		drop_nautilus_uri (panel, pos, dir, "gnome-folder.png");
956
	} else {
957
		if (panel_is_program_in_path  ("gmc-client")) {
958
			/* gmc */
959
			char *name;
960
			char *quoted = g_shell_quote (dir);
961
			char *exec = g_strdup_printf ("gmc-client "
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
962
						      "--create-window=%s",
963
						      quoted);
964

965
			g_free (quoted);
966 967 968

			name = g_path_get_basename (dir);
			load_launcher_applet_from_info (name,
969 970 971 972 973 974
							dir,
							exec,
							"gnome-folder.png",
							panel,
							pos,
							TRUE);
Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
975
			g_free (exec);
976
			g_free (name);
977 978 979 980 981 982
		} else {
			drop_menu (panel, pos, dir);
		}
	}
}

983
static void
984 985
drop_urilist (PanelWidget *panel, int pos, char *urilist,
	      gboolean background_drops)
986 987 988
{
	GList *li, *files;

989
	files = gnome_vfs_uri_list_parse (urilist);
990

991 992 993
	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);
994
		const char *mimetype;
995 996
		char *basename;
		char *dirname;
997
		char *filename;
998
		GnomeVFSFileInfo *info;
999

1000 1001 1002 1003 1004 1005 1006
		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) {
1007 1008 1009
			/* 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. */
1010
			drop_url (panel, pos, uri);
1011 1012 1013
			continue;
		}

1014 1015 1016 1017
		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 ();
1018

1019 1020 1021 1022
		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;
1023 1024
		}

1025 1026
		if (background_drops &&
		    mimetype != NULL &&
1027 1028 1029 1030
		    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 */
		    (filename = extract_filename (uri)) != NULL) {
1031
			panel_widget_set_back_pixmap (panel, filename);
1032 1033 1034 1035 1036 1037 1038 1039 1040
			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);
1041
		} else if (mimetype != NULL &&
1042 1043
			   (strcmp(mimetype, "application/x-gnome-app-info") == 0 ||
			    strcmp(mimetype, "application/x-kde-app-info") == 0)) {
1044
			Launcher *launcher;
1045
			
1046
			launcher = load_launcher_applet (uri, panel, pos, TRUE);
1047
			
1048 1049
			if (launcher != NULL)
				launcher_hoard (launcher);
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061
		} 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) &&
			   (filename = extract_filename (uri)) != NULL) {
			/* executable and local, so add a launcher with
			 * it */
1062
			ask_about_launcher (filename, panel, pos, TRUE);
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079
			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);
1080
		g_free (uri);
1081 1082
	}

1083
	gnome_vfs_uri_list_free (files);
1084 1085
}

1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
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);
}

1100
static void
1101
drop_bgimage (PanelWidget *panel, const char *bgimage)
1102 1103 1104
{
	char *filename;

1105
	filename = extract_filename (bgimage);
1106
	if (filename != NULL) {
1107
		panel_widget_set_back_pixmap (panel, filename);
1108

1109
		g_free (filename);
1110 1111 1112
	}
}

1113
static void
1114 1115
drop_internal_icon (PanelWidget *panel, int pos, const char *icon_name,
		    int action)
1116
{
1117 1118 1119
	Launcher *old_launcher, *launcher;

	if (icon_name == NULL)
1120
		return;
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138

	if (action == GDK_ACTION_MOVE) {
		old_launcher = find_launcher (icon_name);
	} else {
		old_launcher = NULL;
	}

	launcher = load_launcher_applet (icon_name, panel, pos, TRUE);

	if (launcher != NULL) {
		launcher_hoard (launcher);

		if (old_launcher != NULL &&
		    old_launcher->button != NULL)
			gtk_widget_destroy (old_launcher->button);
	}
}

1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
static void
move_applet (PanelWidget *panel, int pos, int applet_num)
{
	AppletInfo *info = g_slist_nth_data (applets, applet_num);

	if (pos < 0)
		pos = 0;

	if (info != NULL &&
	    info->widget != NULL &&
	    info->widget->parent != NULL &&
1150
	    PANEL_IS_WIDGET (info->widget->parent)) {
1151
		GSList *forb;
1152 1153
		forb = g_object_get_data (G_OBJECT (info->widget),
					  PANEL_APPLET_FORBIDDEN_PANELS);
1154 1155 1156 1157 1158 1159 1160 1161
		if ( ! g_slist_find (forb, panel))
			panel_widget_reparent (PANEL_WIDGET (info->widget->parent),
					       panel,
					       info->widget,
					       pos);
	}
}

1162
static void
1163 1164
drop_internal_applet (PanelWidget *panel, int pos, const char *applet_type,
		      int action)
1165
{
1166 1167 1168
	int applet_num = -1;
	gboolean remove_applet = FALSE;

Jiri (George) Lebl's avatar