floating-widget.c 14.5 KB
Newer Older
1 2 3 4 5 6 7 8
/* Gnome panel: floating widget
 * (C) 1999 the Free Software Foundation
 *
 * Authors:  Jacob Berkman
 *           George Lebl
 *
 */

9 10
#include "config.h"

11 12
#include "floating-widget.h"
#include "border-widget.h"
13
#include "panel-marshal.h"
14
#include "panel-config-global.h"
15
#include "foobar-widget.h"
16
#include "panel-util.h"
17
#include "panel-gconf.h"
18
#include "multiscreen-stuff.h"
19 20

static void floating_pos_class_init (FloatingPosClass *klass);
21
static void floating_pos_instance_init (FloatingPos *pos);
22 23

static void floating_pos_set_hidebuttons (BasePWidget *basep);
24
static PanelOrient floating_pos_get_applet_orient (BasePWidget *basep);
25

26
static PanelOrient floating_pos_get_hide_orient (BasePWidget *basep);
27
static void floating_pos_get_hide_pos (BasePWidget *basep,
28
				     PanelOrient hide_orient,
29 30
				     int *x, int *y,
				     int w, int h);
31 32

static void floating_pos_get_pos(BasePWidget *basep,
33 34
				 int *x, int *y,
				 int w, int h);
35 36

static void floating_pos_set_pos (BasePWidget *basep,
37
				  int x, int y,
38 39
				  int w, int h,
				  gboolean force);
40 41

static void floating_pos_get_hide_size (BasePWidget *basep,
42
					PanelOrient hide_orient,
43
					int *x, int *y);
44 45 46 47

static void floating_pos_get_menu_pos (BasePWidget *basep,
				       GtkWidget *widget,
				       GtkRequisition *mreq,
48 49 50
				       int *x, int *y,
				       int wx, int wy,
				       int ww, int wh);
51 52 53

static void floating_pos_pre_convert_hook (BasePWidget *basep);

54 55
static void floating_pos_show_hide_left (BasePWidget *basep);
static void floating_pos_show_hide_right (BasePWidget *basep);
56

57
static BasePPosClass *floating_pos_parent_class;
58

Jiri (George) Lebl's avatar
Jiri (George) Lebl committed
59
GType
60
floating_pos_get_type (void)
61
{
62 63 64 65 66 67 68 69 70 71 72 73 74
	static GType object_type= 0;

	if (object_type == 0) {
		static const GTypeInfo object_info = {
                    sizeof (FloatingPosClass),
                    (GBaseInitFunc)         NULL,
                    (GBaseFinalizeFunc)     NULL,
                    (GClassInitFunc)        floating_pos_class_init,
                    NULL,                   /* class_finalize */
                    NULL,                   /* class_data */
                    sizeof (FloatingPos),
                    0,                      /* n_preallocs */
                    (GInstanceInitFunc)     floating_pos_instance_init
75 76
		};

77 78
		object_type = g_type_register_static (BASEP_TYPE_POS, "FloatingPos", &object_info, 0);
		floating_pos_parent_class = g_type_class_ref (BASEP_TYPE_POS);
79 80
	}

81
	return object_type;
82 83 84 85 86 87
}

enum {
	COORDS_CHANGE_SIGNAL,
	LAST_SIGNAL
};
88
static guint floating_pos_signals[LAST_SIGNAL] = { 0 };
89 90 91 92

static void
floating_pos_class_init (FloatingPosClass *klass)
{
93 94
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	BasePPosClass *pos_class = BASEP_POS_CLASS (klass);
95 96

	floating_pos_signals[COORDS_CHANGE_SIGNAL] =
97 98 99 100 101 102 103 104 105 106 107
		g_signal_new ("floating_coords_change",
			      G_TYPE_FROM_CLASS (object_class),
			      G_SIGNAL_RUN_LAST,
			      G_STRUCT_OFFSET (FloatingPosClass, coords_change),
			      NULL,
			      NULL,
			      panel_marshal_INT__INT,
			      G_TYPE_NONE,
			      2,
			      G_TYPE_INT,
			      G_TYPE_INT);
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
	
	/* fill out the virtual funcs */
	pos_class->set_hidebuttons = floating_pos_set_hidebuttons;
	pos_class->get_applet_orient = floating_pos_get_applet_orient;
	pos_class->get_hide_orient = floating_pos_get_hide_orient;
	pos_class->get_hide_pos = floating_pos_get_hide_pos;
	pos_class->get_hide_size = floating_pos_get_hide_size;
	pos_class->get_pos = floating_pos_get_pos;
	pos_class->set_pos = floating_pos_set_pos;
	pos_class->get_menu_pos = floating_pos_get_menu_pos;
	pos_class->pre_convert_hook = floating_pos_pre_convert_hook;
	pos_class->north_clicked = pos_class->west_clicked = 
		floating_pos_show_hide_left;
	pos_class->south_clicked = pos_class->east_clicked =
		floating_pos_show_hide_right;
}

static void
126
floating_pos_instance_init (FloatingPos *pos) { }
127 128 129 130

static void
floating_pos_set_hidebuttons (BasePWidget *basep)
{
131
	if (PANEL_WIDGET(basep->panel)->orient == GTK_ORIENTATION_HORIZONTAL) {
132 133 134 135 136 137 138 139 140 141 142 143
		gtk_widget_hide(basep->hidebutton_n);
		gtk_widget_show(basep->hidebutton_e);
		gtk_widget_show(basep->hidebutton_w);
		gtk_widget_hide(basep->hidebutton_s);
	} else { /*vertical*/
		gtk_widget_show(basep->hidebutton_n);
		gtk_widget_hide(basep->hidebutton_e);
		gtk_widget_hide(basep->hidebutton_w);
		gtk_widget_show(basep->hidebutton_s);
	}
}

144
static PanelOrient
145 146 147
floating_pos_get_applet_orient (BasePWidget *basep)
{
	PanelWidget *panel = PANEL_WIDGET (basep->panel);
148
	if (panel->orient == GTK_ORIENTATION_HORIZONTAL)
149 150 151
		return (FLOATING_POS (basep->pos)->y -
			multiscreen_y (basep->screen) < 
			multiscreen_height (basep->screen) / 2)
152
			? PANEL_ORIENT_DOWN : PANEL_ORIENT_UP;
153
	else
154 155 156
		return (FLOATING_POS (basep->pos)->x -
		       	multiscreen_x (basep->screen) < 
			multiscreen_width (basep->screen) /2)
157
			? PANEL_ORIENT_RIGHT : PANEL_ORIENT_LEFT;
158 159
}

160
static PanelOrient
161 162
floating_pos_get_hide_orient (BasePWidget *basep)
{
163
	FloatingPos *pos = FLOATING_POS (basep->pos);
164 165 166 167
	PanelWidget *panel = PANEL_WIDGET (basep->panel);

	switch (basep->state) {
	case BASEP_HIDDEN_LEFT:
168
		return (panel->orient == GTK_ORIENTATION_HORIZONTAL)
169
			? PANEL_ORIENT_LEFT : PANEL_ORIENT_UP;
170
	case BASEP_HIDDEN_RIGHT:
171
		return (panel->orient == GTK_ORIENTATION_HORIZONTAL)
172
			? PANEL_ORIENT_RIGHT : PANEL_ORIENT_DOWN;
173
	case BASEP_AUTO_HIDDEN:
174
		if (panel->orient == GTK_ORIENTATION_HORIZONTAL) {
175 176 177 178
			return ((pos->x >
				 (multiscreen_width (basep->screen) +
				  multiscreen_x (basep->screen) - pos->x -
				  basep->shown_alloc.width))
179
				? PANEL_ORIENT_RIGHT : PANEL_ORIENT_LEFT);
180
		} else {
181 182 183 184
			return ((pos->y >
				 (multiscreen_height (basep->screen) +
				  multiscreen_y (basep->screen) - pos->y -
				  basep->shown_alloc.height))
185
				? PANEL_ORIENT_DOWN : PANEL_ORIENT_UP);
186
		}
187 188 189 190 191 192 193 194 195 196
	default:
		g_warning ("not hidden");
		return -1;
	}
}

static void
floating_pos_get_menu_pos (BasePWidget *basep,
			   GtkWidget *widget,
			   GtkRequisition *mreq,
197 198 199
			   int *x, int *y,
			   int wx, int wy,
			   int ww, int wh)
200
{	
201
	PanelOrient menu_orient = floating_pos_get_applet_orient (basep);
202
	
203
	switch (menu_orient) {
204
	case PANEL_ORIENT_DOWN:
205 206 207
		*x += wx;
		*y = wy + wh;
		break;
208
	case PANEL_ORIENT_LEFT:
209
		*x = wx - mreq->width;
210
		*y += wy;
211 212
		break;
	default:
213
	case PANEL_ORIENT_UP:
214 215
		*x += wx;
		*y = wy - mreq->height;
216
		break;
217
	case PANEL_ORIENT_RIGHT:
218 219 220
		*x = wx + ww;
		*y += wy;
		break;
221 222 223
	}
}

224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
static int
xclamp (int screen, int x, int w)
{
	return CLAMP (x, 0,
		      multiscreen_width (screen) - w);
}

static int
yclamp (int screen, int y, int h)
{
	return CLAMP (y, 0, 
		      multiscreen_height (screen) - h -
		      foobar_widget_get_height (screen));
}

239 240
static void
floating_pos_set_pos (BasePWidget *basep,
241
		      int x, int y,
242 243
		      int w, int h,
		      gboolean force)
244 245 246 247
{
	FloatingPos *pos = FLOATING_POS(basep->pos);
	gint16 newx, newy;

248 249
	x -= basep->offset_x;
	y -= basep->offset_y;
250

251 252
	x -= multiscreen_x (basep->screen);
	y -= multiscreen_y (basep->screen);
253

254
	if (PANEL_WIDGET (basep->panel)->orient == GTK_ORIENTATION_HORIZONTAL) {
255 256 257 258 259 260
		switch (basep->state) {
		case BASEP_SHOWN:
		case BASEP_MOVING:
			break;
		case BASEP_AUTO_HIDDEN:
		case BASEP_HIDDEN_LEFT:
261
			w = get_requisition_width (basep->hidebutton_w);
262 263
			break;
		case BASEP_HIDDEN_RIGHT:
264
			w = get_requisition_width (basep->hidebutton_e);
265
			break;
266 267 268
		}
	}

269
	newx = xclamp (basep->screen, x, w);
270

271
	if (PANEL_WIDGET (basep->panel)->orient == GTK_ORIENTATION_VERTICAL) {
272 273 274 275 276 277
		switch (basep->state) {
		case BASEP_SHOWN:
		case BASEP_MOVING:
			break;
		case BASEP_AUTO_HIDDEN:
		case BASEP_HIDDEN_LEFT:
278
			h = get_requisition_height (basep->hidebutton_n);
279 280
			break;
		case BASEP_HIDDEN_RIGHT:
281
			h = get_requisition_height (basep->hidebutton_s);
282
			break;
283 284
		}
	}
285
	newy = yclamp (basep->screen, y, h);
286 287 288 289

	if (newy != pos->y || newx != pos->x) {
		pos->x = newx;
		pos->y = newy;
290 291 292
		g_signal_emit (G_OBJECT (pos),
			       floating_pos_signals[COORDS_CHANGE_SIGNAL],
			       0, pos->x, pos->y);
293 294 295 296 297 298
		gtk_widget_queue_resize (GTK_WIDGET (basep));
	}
}

static void
floating_pos_get_pos(BasePWidget *basep,
299 300
		     int *x, int *y,
		     int w, int h)
301
{
302 303 304 305
	*x = xclamp (basep->screen, FLOATING_POS (basep->pos)->x, w);
	*y = yclamp (basep->screen, FLOATING_POS (basep->pos)->y, h);
	*x += multiscreen_x (basep->screen);
	*y += multiscreen_y (basep->screen);
306 307 308 309
}

static void
floating_pos_get_hide_size (BasePWidget *basep, 
310
			    PanelOrient hide_orient,
311
			    int *w, int *h)
312
{
313 314
	gchar *panel_global_key;

315 316
	if (basep->state == BASEP_AUTO_HIDDEN &&
	    ! basep->hidebuttons_enabled) {
317 318
		panel_global_key = panel_gconf_global_config_get_full_key ("panel_minimized-size");

319
		switch (hide_orient) {
320 321
		case PANEL_ORIENT_UP:
		case PANEL_ORIENT_DOWN:
322
			*h = panel_gconf_get_int (panel_global_key);
323
			break;
324 325
		case PANEL_ORIENT_LEFT:
		case PANEL_ORIENT_RIGHT:
326
			*w = panel_gconf_get_int (panel_global_key);
327 328
			break;
		}
329 330

		g_free (panel_global_key);
331 332
	} else {
		switch (hide_orient) {
333
		case PANEL_ORIENT_UP:
334 335
			*h = get_requisition_height (basep->hidebutton_n);
			break;
336
		case PANEL_ORIENT_RIGHT:
337 338
			*w = get_requisition_width (basep->hidebutton_w);
			break;
339
		case PANEL_ORIENT_DOWN:
340 341
			*h = get_requisition_height (basep->hidebutton_s);
			break;
342
		case PANEL_ORIENT_LEFT:
343
			*w = get_requisition_width (basep->hidebutton_e);
344 345
			break;
		}
346
	}
347 348 349 350
	/* minimum of 3x3 pixels, as 1x1 is impossible to hit in case
	 * something goes wrong */
	*w = MAX (*w, 3);
	*h = MAX (*h, 3);
351 352 353 354
}

static void
floating_pos_get_hide_pos (BasePWidget *basep,
355
			   PanelOrient hide_orient,
356 357
			   int *x, int *y,
			   int w, int h)
358
{
359 360 361 362
	gchar *panel_global_key;

	panel_global_key = panel_gconf_global_config_get_full_key ("panel_minimized-size");

363
	switch (hide_orient) {
364 365
	case PANEL_ORIENT_UP:
	case PANEL_ORIENT_LEFT:
366
		break;
367
	case PANEL_ORIENT_RIGHT:
368 369
		*x += w - ((basep->state == BASEP_AUTO_HIDDEN &&
			    ! basep->hidebuttons_enabled)
370
			   ? panel_gconf_get_int (panel_global_key)
371
			   : get_requisition_width (basep->hidebutton_w));
372
		break;
373
	case PANEL_ORIENT_DOWN:
374 375
		*y += h - ((basep->state == BASEP_AUTO_HIDDEN &&
			    ! basep->hidebuttons_enabled)
376
			   ? panel_gconf_get_int (panel_global_key)
377
			   : get_requisition_height (basep->hidebutton_s));
378 379
		break;
	}
380 381
	
	g_free (panel_global_key);
382 383
}

384
static void
385 386 387 388 389 390 391 392 393
floating_pos_show_hide_left (BasePWidget *basep)
{
	switch (basep->state) {
	case BASEP_SHOWN:
		basep_widget_explicit_hide (basep, BASEP_HIDDEN_LEFT);
		break;
	case BASEP_HIDDEN_RIGHT:
		basep_widget_explicit_show (basep);
		break;
394
	default:
395 396 397 398
		break;
	}
}

399
static void
400 401 402 403 404 405 406 407 408
floating_pos_show_hide_right (BasePWidget *basep)
{
	switch (basep->state) {
	case BASEP_SHOWN:
		basep_widget_explicit_hide (basep, BASEP_HIDDEN_RIGHT);
		break;
	case BASEP_HIDDEN_LEFT:
		basep_widget_explicit_show (basep);
		break;
409
	default:
410 411 412 413 414 415 416 417 418 419 420 421 422
		break;
	}
}

static void
floating_pos_pre_convert_hook (BasePWidget *basep)
{
	basep->keep_in_screen = TRUE;
	PANEL_WIDGET (basep->panel)->packed = TRUE;
}

void 
floating_widget_change_params (FloatingWidget *floating,
423 424 425
			       int screen,
			       gint16 x,
			       gint16 y,
426
			       GtkOrientation orient,
427 428
			       BasePMode mode,
			       BasePState state,
429
			       int sz,
430 431
			       gboolean hidebuttons_enabled,
			       gboolean hidebutton_pixmap_enabled,
432 433
			       PanelBackType back_type,
			       char *back_pixmap,
434 435 436
			       gboolean fit_pixmap_bg,
			       gboolean strech_pixmap_bg,
			       gboolean rotate_pixmap_bg,
437 438
			       GdkColor *back_color)
{
439 440
	BasePWidget *basep = BASEP_WIDGET (floating);
	FloatingPos *pos = FLOATING_POS (basep->pos);
441

442
	if (PANEL_WIDGET (basep->panel)->orient != orient)
443 444
		BASEP_WIDGET (floating)->request_cube = TRUE;

445 446
	x = xclamp (basep->screen, x, basep->shown_alloc.width);
	y = yclamp (basep->screen, y, basep->shown_alloc.height);
447 448 449 450

	if (y != pos->y || x != pos->x) {
		pos->x = x;
		pos->y = y;
451 452 453
		g_signal_emit (G_OBJECT (pos),
			       floating_pos_signals[COORDS_CHANGE_SIGNAL],
			       0, x, y);
454 455
	}

456
	basep_widget_change_params (basep,
457 458 459 460 461
				    screen,
				    orient,
				    sz,
				    mode,
				    state,
462 463
				    hidebuttons_enabled,
				    hidebutton_pixmap_enabled,
464 465 466 467
				    back_type,
				    back_pixmap,
				    fit_pixmap_bg,
				    strech_pixmap_bg,
468 469
				    rotate_pixmap_bg,
				    back_color);
470 471 472 473 474
				    
}

void
floating_widget_change_orient (FloatingWidget *floating,
475
			       GtkOrientation orient)
476 477 478 479 480 481
{
	FloatingPos *pos = FLOATING_POS (floating->pos);
	if (PANEL_WIDGET (BASEP_WIDGET (floating)->panel)->orient != orient) {
		BasePWidget *basep = BASEP_WIDGET (floating);
		PanelWidget *panel = PANEL_WIDGET (basep->panel);
		floating_widget_change_params (floating, 
482 483 484
					       basep->screen,
					       pos->x,
					       pos->y,
485 486 487 488 489
					       orient,
					       basep->mode,
					       basep->state,
					       panel->sz,
					       basep->hidebuttons_enabled,
490 491 492 493
					       basep->hidebutton_pixmaps_enabled,
					       panel->back_type,
					       panel->back_pixmap,
					       panel->fit_pixmap_bg,
494 495
					       panel->strech_pixmap_bg,
					       panel->rotate_pixmap_bg,
496 497 498 499 500 501 502 503 504 505 506 507 508
					       &panel->back_color);
	}
}

void
floating_widget_change_coords (FloatingWidget *floating,
			       gint16 x, gint16 y)
{
	FloatingPos *pos = FLOATING_POS (floating->pos);
	if (pos->x != x || pos->y != y) {
		BasePWidget *basep = BASEP_WIDGET (floating);
		PanelWidget *panel = PANEL_WIDGET (basep->panel);
		floating_widget_change_params (floating, 
509 510 511
					       basep->screen,
					       x,
					       y,
512 513 514 515 516
					       panel->orient,
					       basep->mode,
					       basep->state,
					       panel->sz,
					       basep->hidebuttons_enabled,
517 518 519 520
					       basep->hidebutton_pixmaps_enabled,
					       panel->back_type,
					       panel->back_pixmap,
					       panel->fit_pixmap_bg,
521 522
					       panel->strech_pixmap_bg,
					       panel->rotate_pixmap_bg,
523 524 525 526 527
					       &panel->back_color);
	}
}

GtkWidget *
528 529 530
floating_widget_new (int screen,
		     gint16 x,
		     gint16 y,
531
		     GtkOrientation orient,
532 533
		     BasePMode mode,
		     BasePState state,
534
		     int sz,
535 536
		     gboolean hidebuttons_enabled,
		     gboolean hidebutton_pixmap_enabled,
537 538
		     PanelBackType back_type,
		     char *back_pixmap,
539 540 541
		     gboolean fit_pixmap_bg,
		     gboolean strech_pixmap_bg,
		     gboolean rotate_pixmap_bg,
542 543 544 545 546
		     GdkColor *back_color)
{
	FloatingWidget *floating;
	FloatingPos *pos;

547 548
	floating = gtk_type_new (FLOATING_TYPE_WIDGET);
	floating->pos = gtk_type_new (FLOATING_TYPE_POS);
549 550 551 552 553 554 555
	pos = FLOATING_POS (floating->pos);

	pos->x = x;
	pos->y = y;

	basep_widget_construct (BASEP_WIDGET (floating),
				TRUE, FALSE,
556
				screen,
557
				orient,
558 559 560
				sz,
				mode,
				state,
561 562 563 564 565
				hidebuttons_enabled,
				hidebutton_pixmap_enabled,
				back_type,
				back_pixmap,
				fit_pixmap_bg,
566 567
				strech_pixmap_bg,
				rotate_pixmap_bg,
568 569 570 571
				back_color);

	return GTK_WIDGET (floating);
}