input-dialog.c 32 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
Sven Neumann's avatar
Sven Neumann committed
18

Tor Lillqvist's avatar
Tor Lillqvist committed
19 20
#include "config.h"

21
#include <stdio.h>
22 23
#include <string.h>

24
#include <gtk/gtk.h>
Sven Neumann's avatar
Sven Neumann committed
25

26
#include "libgimpcolor/gimpcolor.h"
27
#include "libgimpbase/gimpbase.h"
28
#include "libgimpwidgets/gimpwidgets.h"
29

Sven Neumann's avatar
Sven Neumann committed
30
#include "apptypes.h"
31
#include "widgets/widgets-types.h"
Sven Neumann's avatar
Sven Neumann committed
32

33 34 35 36 37 38
#include "core/gimpbrush.h"
#include "core/gimpcontainer.h"
#include "core/gimpcontext.h"
#include "core/gimpdatafactory.h"
#include "core/gimpgradient.h"
#include "core/gimppattern.h"
Michael Natterer's avatar
Michael Natterer committed
39
#include "core/gimptoolinfo.h"
40

Michael Natterer's avatar
Michael Natterer committed
41
#include "widgets/gimpdnd.h"
42 43
#include "widgets/gimppreview.h"

44 45
#include "tools/tool_manager.h"

46
#include "appenv.h"
47
#include "context_manager.h"
48 49
#include "devices.h"
#include "dialog_handler.h"
50
#include "gimprc.h"
51

52 53
#include "libgimp/gimpintl.h"

54

55
#define CELL_SIZE 20 /* The size of the preview cells */
56

57 58 59 60 61 62
#define DEVICE_CONTEXT_MASK (GIMP_CONTEXT_TOOL_MASK       | \
                             GIMP_CONTEXT_FOREGROUND_MASK | \
                             GIMP_CONTEXT_BACKGROUND_MASK | \
			     GIMP_CONTEXT_BRUSH_MASK      | \
			     GIMP_CONTEXT_PATTERN_MASK    | \
                             GIMP_CONTEXT_GRADIENT_MASK)
63

64

65 66
typedef struct _DeviceInfo DeviceInfo;

67 68 69 70 71 72
struct _DeviceInfo
{
  guint32       device;      /*  device ID  */
  gchar        *name;

  gshort        is_present;  /*  is the device currently present  */
73

74
  /*  gdk_input options - for not present devices  */
75

76 77 78 79
  GdkInputMode  mode;
  gint          num_axes;
  GdkAxisUse   *axes;
  gint          num_keys;
80 81
  GdkDeviceKey *keys;

82
  GimpContext  *context;
83 84 85 86
};

typedef struct _DeviceInfoDialog DeviceInfoDialog;

87 88 89 90 91 92
struct _DeviceInfoDialog
{
  gint       num_devices;

  guint32    current;
  guint32   *ids;
93 94 95 96 97 98

  GtkWidget *shell;
  GtkWidget *table;

  GtkWidget **frames;
  GtkWidget **tools;
99 100
  GtkWidget **foregrounds;
  GtkWidget **backgrounds;
101
  GtkWidget **brushes;
102
  GtkWidget **patterns;
Michael Natterer's avatar
Michael Natterer committed
103
  GtkWidget **gradients;
104 105
};

106

107
/*  local functions */
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
static void     input_dialog_able_callback       (GtkWidget    *widget,
						  guint32       deviceid, 
						  gpointer      data);

static void     devices_write_rc_device          (DeviceInfo   *device_info,
						  FILE         *fp);
static void     devices_write_rc                 (void);

static void     device_status_destroy_callback   (void);
static void     devices_close_callback           (GtkWidget    *widget,
						  gpointer      data);

static void     device_status_update             (guint32       deviceid);
static void     device_status_update_current     (void);

static void     device_status_drop_tool          (GtkWidget    *widget,
124
						  GimpViewable *viewable,
125 126 127 128 129 130
						  gpointer      data);
static void     device_status_foreground_changed (GtkWidget    *widget,
						  gpointer      data);
static void     device_status_background_changed (GtkWidget    *widget,
						  gpointer      data);
static void     device_status_drop_brush         (GtkWidget    *widget,
131
						  GimpViewable *viewable,
132 133
						  gpointer      data);
static void     device_status_drop_pattern       (GtkWidget    *widget,
134
						  GimpViewable *viewable,
135 136
						  gpointer      data);
static void     device_status_drop_gradient      (GtkWidget    *widget,
137
						  GimpViewable *viewable,
138 139 140 141 142 143 144 145
						  gpointer      data);

static void     device_status_data_changed       (GimpContext  *context,
						  gpointer      dummy,
						  gpointer      data);

static void     device_status_context_connect    (GimpContext  *context,
						  guint32       deviceid);
Sven Neumann's avatar
Sven Neumann committed
146

147

148 149
/*  global data  */
gint current_device = GDK_CORE_POINTER;
150

151 152 153 154 155 156
/*  local data  */
static GList            *device_info_list = NULL;
static DeviceInfoDialog *deviceD          = NULL;

/*  if true, don't update device information dialog */
static gboolean          suppress_update  = FALSE;
157

158

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
/*  utility functions for the device lists  */

static GdkDeviceInfo *
gdk_device_info_get_by_id (guint32 deviceid)
{
  GdkDeviceInfo *info;
  GList *list;

  for (list = gdk_input_list_devices (); list; list = g_list_next (list))
    {
      info = (GdkDeviceInfo *) list->data;

      if (info->deviceid == deviceid)
	return info;
    }

  return NULL;
}

static DeviceInfo *
device_info_get_by_id (guint32 deviceid)
{
  DeviceInfo *info;
  GList *list;

  for (list = device_info_list; list; list = g_list_next (list))
    {
      info = (DeviceInfo *) list->data;

      if (info->device == deviceid)
	return info;
    }

  return NULL;
}

static DeviceInfo *
device_info_get_by_name (gchar *name)
{
  DeviceInfo *info;
  GList *list;

  for (list = device_info_list; list; list = g_list_next (list))
    {
      info = (DeviceInfo *) list->data;

      if (!strcmp (info->name, name))
	return info;
    }

  return NULL;
}

/*  the gtk input dialog  */
Sven Neumann's avatar
Sven Neumann committed
213

214
GtkWidget *
215
input_dialog_create (void)
216 217
{
  static GtkWidget *inputd = NULL;
Michael Natterer's avatar
Michael Natterer committed
218
  GtkWidget        *hbbox;
219

220 221
  if (inputd)
    return inputd;
222

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
  inputd = gtk_input_dialog_new ();

  /* register this one only */
  dialog_register (inputd);

  gtk_container_set_border_width
    (GTK_CONTAINER (GTK_DIALOG (inputd)->action_area), 2);
  gtk_box_set_homogeneous (GTK_BOX (GTK_DIALOG (inputd)->action_area),
			   FALSE);

  hbbox = gtk_hbutton_box_new ();
  gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbbox), 4);

  gtk_widget_reparent (GTK_INPUT_DIALOG (inputd)->save_button, hbbox);
  GTK_WIDGET_SET_FLAGS (GTK_INPUT_DIALOG (inputd)->save_button,
			GTK_CAN_DEFAULT);
  gtk_widget_reparent (GTK_INPUT_DIALOG (inputd)->close_button, hbbox);
  GTK_WIDGET_SET_FLAGS (GTK_INPUT_DIALOG (inputd)->close_button,
			GTK_CAN_DEFAULT);

  gtk_box_pack_end (GTK_BOX (GTK_DIALOG (inputd)->action_area), hbbox,
		    FALSE, FALSE, 0);
  gtk_widget_grab_default (GTK_INPUT_DIALOG (inputd)->close_button);
  gtk_widget_show(hbbox);

  gtk_signal_connect (GTK_OBJECT (GTK_INPUT_DIALOG (inputd)->save_button),
		      "clicked",
		      GTK_SIGNAL_FUNC (devices_write_rc),
		      NULL);
  gtk_signal_connect (GTK_OBJECT (GTK_INPUT_DIALOG (inputd)->close_button),
		      "clicked",
		      GTK_SIGNAL_FUNC (devices_close_callback),
		      inputd);

  gtk_signal_connect (GTK_OBJECT (inputd), "destroy",
		      GTK_SIGNAL_FUNC (gtk_widget_destroyed),
		      &inputd);

  gtk_signal_connect (GTK_OBJECT (inputd), "enable_device",
		      GTK_SIGNAL_FUNC (input_dialog_able_callback),
		      NULL);
  gtk_signal_connect (GTK_OBJECT (inputd), "disable_device",
		      GTK_SIGNAL_FUNC (input_dialog_able_callback),
		      NULL);

  /*  Connect the "F1" help key  */
  gimp_help_connect_help_accel (inputd,
				gimp_standard_help_func,
				"dialogs/input_devices.html");

  return inputd;
274 275
}

276
static void
277 278
input_dialog_able_callback (GtkWidget *widget,
			    guint32    deviceid,
279
			    gpointer   data)
280 281 282 283 284 285 286
{
  device_status_update (deviceid);
}

void 
devices_init (void)
{
287 288 289
  GdkDeviceInfo *gdk_info;
  DeviceInfo    *device_info;
  GList         *list;
290

291 292
  /*  create device info structures for present devices */
  for (list = gdk_input_list_devices (); list; list = g_list_next (list))
293
    {
294
      gdk_info = (GdkDeviceInfo *) list->data;
295

296
      device_info = g_new (DeviceInfo, 1);
297

298 299
      device_info->device     = gdk_info->deviceid;
      device_info->name       = g_strdup (gdk_info->name);
300 301
      device_info->is_present = TRUE;

302 303 304 305 306 307 308 309 310 311 312 313 314
      device_info->mode       = gdk_info->mode;
      device_info->num_axes   = gdk_info->num_axes;
      device_info->axes       = NULL;

      device_info->context    = gimp_context_new (device_info->name, NULL);
      gimp_context_define_args (device_info->context,
				DEVICE_CONTEXT_MASK,
				FALSE);
      gimp_context_copy_args (gimp_context_get_user (), device_info->context,
			      DEVICE_CONTEXT_MASK);
      device_status_context_connect (device_info->context, device_info->device);

      device_info_list = g_list_append (device_info_list, device_info);
315
    }
Sven Neumann's avatar
Sven Neumann committed
316 317 318
}

void
319
devices_restore (void)
320
{
321
  DeviceInfo  *device_info;
322
  GimpContext *context;
323
  gchar       *filename;
Sven Neumann's avatar
Sven Neumann committed
324

325
  /* Augment with information from rc file */
Tor Lillqvist's avatar
Tor Lillqvist committed
326 327 328
  filename = gimp_personal_rc_file ("devicerc");
  parse_gimprc_file (filename);
  g_free (filename);
Sven Neumann's avatar
Sven Neumann committed
329

330 331
  if ((device_info = device_info_get_by_id (current_device)) == NULL)
    return;
332

Sven Neumann's avatar
Sven Neumann committed
333 334
  suppress_update = TRUE;

335 336 337 338
  context = gimp_context_get_user ();

  gimp_context_copy_args (device_info->context, context, DEVICE_CONTEXT_MASK);
  gimp_context_set_parent (device_info->context, context);
339

Sven Neumann's avatar
Sven Neumann committed
340
  suppress_update = FALSE;
341 342 343
}

void
344 345 346 347 348 349 350
devices_rc_update (gchar        *name, 
		   DeviceValues  values,
		   GdkInputMode  mode, 
		   gint          num_axes,
		   GdkAxisUse   *axes, 
		   gint          num_keys, 
		   GdkDeviceKey *keys,
351
		   const gchar  *tool_name,
352 353
		   GimpRGB      *foreground,
		   GimpRGB      *background,
354 355 356
		   const gchar  *brush_name, 
		   const gchar  *pattern_name,
		   const gchar  *gradient_name)
357 358 359
{
  DeviceInfo *device_info;

360 361
  /*  Find device if we have it  */
  device_info = device_info_get_by_name (name);
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

  if (!device_info)
    {
      device_info = g_new (DeviceInfo, 1);
      device_info->name = g_strdup (name);
      device_info->is_present = FALSE;

      if (values & DEVICE_AXES)
	{
	  device_info->num_axes = num_axes;
	  device_info->axes = g_new (GdkAxisUse, num_axes);
	  memcpy (device_info->axes, axes, num_axes * sizeof (GdkAxisUse));
	}
      else
	{
	  device_info->num_axes = 0;
	  device_info->axes = NULL;
	}

      if (values & DEVICE_KEYS)
	{
	  device_info->num_keys = num_keys;
	  device_info->keys = g_new (GdkDeviceKey, num_keys);
	  memcpy (device_info->keys, axes, num_keys * sizeof (GdkDeviceKey));
	}

      if (values & DEVICE_MODE)
	device_info->mode = mode;
      else
	device_info->mode = GDK_MODE_DISABLED;

393 394 395 396 397 398 399
      device_info->context = gimp_context_new (device_info->name, NULL);
      gimp_context_define_args (device_info->context,
				DEVICE_CONTEXT_MASK,
				FALSE);
      gimp_context_copy_args (gimp_context_get_user (), device_info->context,
			      DEVICE_CONTEXT_MASK);
      device_status_context_connect (device_info->context, device_info->device);
400

401
      device_info_list = g_list_append (device_info_list, device_info);
402 403 404
    }
  else
    {
405
      GdkDeviceInfo *gdk_info;
406

407
      gdk_info = gdk_device_info_get_by_id (device_info->device);
408 409 410 411 412 413 414 415

      if (gdk_info != NULL)
	{
	  if (values & DEVICE_MODE)
	    gdk_input_set_mode (gdk_info->deviceid, mode);
	  
	  if ((values & DEVICE_AXES) && num_axes >= gdk_info->num_axes)
	    gdk_input_set_axes (gdk_info->deviceid, axes);
416

417 418
	  if ((values & DEVICE_KEYS) && num_keys >= gdk_info->num_keys)
	    {
419
	      gint i;
420 421 422 423 424 425 426 427
	      
	      for (i=0; i<MAX (num_keys, gdk_info->num_keys); i++)
		gdk_input_set_key (gdk_info->deviceid, i,
				   keys[i].keyval, keys[i].modifiers);
	    }
	}
      else
	{
Sven Neumann's avatar
Sven Neumann committed
428 429
	  g_warning ("devices_rc_update called multiple times "
		     "for not present device\n");
430 431 432 433
	  return;
	}
    }

434 435
  if (values & DEVICE_TOOL)
    {
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450
      GimpToolInfo *tool_info;

      tool_info = (GimpToolInfo *)
	gimp_container_get_child_by_name (global_tool_info_list,
					  tool_name);

      if (tool_info)
	{
	  gimp_context_set_tool (device_info->context, tool_info);
	}
      else
	{
	  g_free (device_info->context->tool_name);
	  device_info->context->tool_name = g_strdup (tool_name);
	}
451
    }
452

453 454
  if (values & DEVICE_FOREGROUND)
    {
455
      gimp_context_set_foreground (device_info->context, foreground);
456 457 458 459
    }

  if (values & DEVICE_BACKGROUND)
    {
460
      gimp_context_set_background (device_info->context, background);
461
    }
462

463 464
  if (values & DEVICE_BRUSH)
    {
465 466
      GimpBrush *brush;

467
      brush = (GimpBrush *)
468
	gimp_container_get_child_by_name (global_brush_factory->container,
469
					  brush_name);
470 471 472 473 474 475 476 477 478 479

      if (brush)
	{
	  gimp_context_set_brush (device_info->context, brush);
	}
      else if (no_data)
	{
	  g_free (device_info->context->brush_name);
	  device_info->context->brush_name = g_strdup (brush_name);
	}
480 481
    }

482 483
  if (values & DEVICE_PATTERN)
    {
Michael Natterer's avatar
Michael Natterer committed
484
      GimpPattern *pattern;
485

486
      pattern = (GimpPattern *)
487
	gimp_container_get_child_by_name (global_pattern_factory->container,
488
					  pattern_name);
489 490 491 492 493 494 495 496 497 498

      if (pattern)
	{
	  gimp_context_set_pattern (device_info->context, pattern);
	}
      else if (no_data)
	{
	  g_free (device_info->context->pattern_name);
	  device_info->context->pattern_name = g_strdup (pattern_name);
	}
499 500
    }

501
  if (values & DEVICE_GRADIENT)
502
    {
503
      GimpGradient *gradient;
504

505
      gradient = (GimpGradient *)
506
	gimp_container_get_child_by_name (global_gradient_factory->container,
507
					  gradient_name);
508 509 510 511 512 513 514 515 516 517

      if (gradient)
	{
	  gimp_context_set_gradient (device_info->context, gradient);
	}
      else if (no_data)
	{
	  g_free (device_info->context->gradient_name);
	  device_info->context->gradient_name = g_strdup (gradient_name);
	}
518 519 520
    }
}

521
void
522 523 524
select_device (guint32 new_device)
{
  DeviceInfo *device_info;
525 526 527 528 529
  GimpContext *context;

  device_info = device_info_get_by_id (current_device);

  gimp_context_unset_parent (device_info->context);
530 531 532

  suppress_update = TRUE;
  
533
  device_info = device_info_get_by_id (new_device);
534

535
  current_device = new_device;
536

537
  context = gimp_context_get_user ();
538

539 540
  gimp_context_copy_args (device_info->context, context, DEVICE_CONTEXT_MASK);
  gimp_context_set_parent (device_info->context, context);
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566

  suppress_update = FALSE;

  device_status_update_current ();
}

gint
devices_check_change (GdkEvent *event)
{
  guint32 device;

  switch (event->type)
    {
    case GDK_MOTION_NOTIFY:
      device = ((GdkEventMotion *)event)->deviceid;
      break;
    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
      device = ((GdkEventButton *)event)->deviceid;
      break;
    case GDK_PROXIMITY_OUT:
      device = ((GdkEventProximity *)event)->deviceid;
      break;
    default:
      device = current_device;
    }
567

568 569 570 571 572 573 574
  if (device != current_device)
    {
      select_device (device);
      return TRUE;
    }
  else
    {
575
      return FALSE;
576 577 578 579
    }
}

static void
580
devices_write_rc_device (DeviceInfo *device_info,
581
			 FILE       *fp)
582
{
583 584 585
  GdkDeviceInfo *gdk_info = NULL;
  gchar *mode = NULL;
  gint i;
586 587

  if (device_info->is_present)
588
    gdk_info = gdk_device_info_get_by_id (device_info->device);
589
  
590
  fprintf (fp, "(device \"%s\"", device_info->name);
591 592 593 594 595 596 597 598 599 600 601 602 603 604

  switch (gdk_info ? gdk_info->mode : device_info->mode)
    {
    case GDK_MODE_DISABLED:
      mode = "disabled";
      break;
    case GDK_MODE_SCREEN:
      mode = "screen";
      break;
    case GDK_MODE_WINDOW:
      mode = "window";
      break;
    }
  
605
  fprintf (fp, "\n    (mode %s)", mode);
606

607
  fprintf (fp, "\n    (axes %d",
608
	   gdk_info ? gdk_info->num_axes : device_info->num_axes);
609

610
  for (i=0; i< (gdk_info ? gdk_info->num_axes : device_info->num_axes); i++)
611
    {
612
      gchar *axis_type = NULL;
613

614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634
      switch (gdk_info ? gdk_info->axes[i] : device_info->axes[i])
	{
	case GDK_AXIS_IGNORE:
	  axis_type = "ignore";
	  break;
	case GDK_AXIS_X:
	  axis_type = "x";
	  break;
	case GDK_AXIS_Y:
	  axis_type = "y";
	  break;
	case GDK_AXIS_PRESSURE:
	  axis_type = "pressure";
	  break;
	case GDK_AXIS_XTILT:
	  axis_type = "xtilt";
	  break;
	case GDK_AXIS_YTILT:
	  axis_type = "ytilt";
	  break;
	}
635
      fprintf (fp, " %s",axis_type);
636
    }
637
  fprintf (fp,")");
638

639
  fprintf (fp, "\n    (keys %d",
640
	   gdk_info ? gdk_info->num_keys : device_info->num_keys);
641

642
  for (i = 0; i < (gdk_info ? gdk_info->num_keys : device_info->num_keys); i++)
643 644 645 646 647
    {
      GdkModifierType modifiers = gdk_info ? gdk_info->keys[i].modifiers :
	device_info->keys[i].modifiers;
      guint keyval = gdk_info ? gdk_info->keys[i].keyval :
	device_info->keys[i].keyval;
648

649 650 651
      if (keyval)
	{
	  /* FIXME: integrate this back with menus_install_accelerator */
652 653
	  gchar accel[64];
	  gchar t2[2];
654 655 656 657 658 659 660 661

	  accel[0] = '\0';
	  if (modifiers & GDK_CONTROL_MASK)
	    strcat (accel, "<control>");
	  if (modifiers & GDK_SHIFT_MASK)
	    strcat (accel, "<shift>");
	  if (modifiers & GDK_MOD1_MASK)
	    strcat (accel, "<alt>");
662

663 664 665 666 667 668 669 670
	  t2[0] = keyval;
	  t2[1] = '\0';
	  strcat (accel, t2);
	  fprintf (fp, " \"%s\"",accel);
	}
      else
	fprintf (fp, " \"\"");
    }
671
  fprintf (fp,")");
672

673 674
  if (gimp_context_get_tool (device_info->context))
    {
675
      fprintf (fp, "\n    (tool \"%s\")",
676
	       GIMP_OBJECT (gimp_context_get_tool (device_info->context))->name);
677
    }
678 679

  {
680 681 682 683
    GimpRGB color;

    gimp_context_get_foreground (device_info->context, &color);

684 685
    fprintf (fp, "\n    (foreground (color-rgb %f %f %f))",
	     color.r, color.g, color.b);
686 687 688

    gimp_context_get_background (device_info->context, &color);

689 690
    fprintf (fp, "\n    (background (color-rgb %f %f %f))",
	     color.r, color.g, color.b);
691 692 693 694
  }

  if (gimp_context_get_brush (device_info->context))
    {
695
      fprintf (fp, "\n    (brush \"%s\")",
696
	       GIMP_OBJECT (gimp_context_get_brush (device_info->context))->name);
697 698 699 700
    }

  if (gimp_context_get_pattern (device_info->context))
    {
701
      fprintf (fp, "\n    (pattern \"%s\")",
Michael Natterer's avatar
Michael Natterer committed
702
	       GIMP_OBJECT (gimp_context_get_pattern (device_info->context))->name);
703 704
    }

Michael Natterer's avatar
Michael Natterer committed
705 706
  if (gimp_context_get_gradient (device_info->context))
    {
707
      fprintf (fp, "\n    (gradient \"%s\")",
708
	       GIMP_OBJECT (gimp_context_get_gradient (device_info->context))->name);
Michael Natterer's avatar
Michael Natterer committed
709 710
    }

711 712 713 714 715 716
  fprintf(fp,")\n");
}

static void
devices_write_rc (void)
{
717
  DeviceInfo *device_info;
718 719
  gchar      *filename;
  FILE       *fp;
720

721
  device_info = device_info_get_by_id (current_device);
722

Tor Lillqvist's avatar
Tor Lillqvist committed
723 724 725
  filename = gimp_personal_rc_file ("devicerc");
  fp = fopen (filename, "wb");
  g_free (filename);
726

Tor Lillqvist's avatar
Tor Lillqvist committed
727 728
  if (!fp)
    return;
729

730
  g_list_foreach (device_info_list, (GFunc) devices_write_rc_device, fp);
731

Tor Lillqvist's avatar
Tor Lillqvist committed
732
  fclose (fp);
733 734
}

735
GtkWidget *
736
device_status_create (void)
737 738
{
  DeviceInfo *device_info;
739
  GtkWidget  *label;
740
  GimpRGB     color;
741 742
  GList      *list;
  gint        i;
743

744
  if (deviceD)
745
    return deviceD->shell;
746

747
  deviceD = g_new (DeviceInfoDialog, 1);
748

749 750 751 752 753
  deviceD->shell = gimp_dialog_new (_("Device Status"), "device_status",
				    gimp_standard_help_func,
				    "dialogs/device_status.html",
				    GTK_WIN_POS_NONE,
				    FALSE, FALSE, TRUE,
754

755 756 757 758
				    _("Save"), (GtkSignalFunc) devices_write_rc,
				    NULL, NULL, NULL, FALSE, FALSE,
				    _("Close"), devices_close_callback,
				    NULL, NULL, NULL, TRUE, TRUE,
759

760
				    NULL);
761

762
  dialog_register (deviceD->shell);
763

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824
  deviceD->num_devices = 0;

  for (list = device_info_list; list; list = g_list_next (list))
    {
      if (((DeviceInfo *) list->data)->is_present)
	deviceD->num_devices++;
    }

  /*  devices table  */
  deviceD->table = gtk_table_new (deviceD->num_devices, 7, FALSE);
  gtk_container_set_border_width (GTK_CONTAINER (deviceD->table), 3);
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (deviceD->shell)->vbox),
		     deviceD->table);
  gtk_widget_realize (deviceD->table);
  gtk_widget_show (deviceD->table);

  deviceD->ids         = g_new (guint32, deviceD->num_devices);
  deviceD->frames      = g_new (GtkWidget *, deviceD->num_devices);
  deviceD->tools       = g_new (GtkWidget *, deviceD->num_devices);
  deviceD->foregrounds = g_new (GtkWidget *, deviceD->num_devices);
  deviceD->backgrounds = g_new (GtkWidget *, deviceD->num_devices);
  deviceD->brushes     = g_new (GtkWidget *, deviceD->num_devices);
  deviceD->patterns    = g_new (GtkWidget *, deviceD->num_devices);
  deviceD->gradients   = g_new (GtkWidget *, deviceD->num_devices);

  for (list = device_info_list, i = 0; list; list = g_list_next (list), i++)
    {
      if (!((DeviceInfo *) list->data)->is_present)
	continue;

      device_info = (DeviceInfo *) list->data;

      deviceD->ids[i] = device_info->device;

      /*  the device name  */

      deviceD->frames[i] = gtk_frame_new (NULL);

      gtk_frame_set_shadow_type (GTK_FRAME(deviceD->frames[i]), GTK_SHADOW_OUT);
      gtk_table_attach (GTK_TABLE(deviceD->table), deviceD->frames[i],
			0, 1, i, i+1,
			GTK_FILL, GTK_FILL, 2, 0);

      label = gtk_label_new (device_info->name);
      gtk_misc_set_padding (GTK_MISC(label), 2, 0);
      gtk_container_add (GTK_CONTAINER(deviceD->frames[i]), label);
      gtk_widget_show(label);

      /*  the tool  */

      deviceD->tools[i] =
	gimp_preview_new_full (GIMP_VIEWABLE (gimp_context_get_tool (device_info->context)),
			       CELL_SIZE, CELL_SIZE, 0,
			       FALSE, FALSE, TRUE);
      gtk_signal_connect_object_while_alive
	(GTK_OBJECT (device_info->context),
	 "tool_changed",
	 GTK_SIGNAL_FUNC (gimp_preview_set_viewable),
	 GTK_OBJECT (deviceD->tools[i]));
      gimp_gtk_drag_dest_set_by_type (deviceD->tools[i],
				      GTK_DEST_DEFAULT_ALL,
825
				      GIMP_TYPE_TOOL_INFO,
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 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879
				      GDK_ACTION_COPY);
      gimp_dnd_viewable_dest_set (deviceD->tools[i],
				  GIMP_TYPE_TOOL_INFO,
				  device_status_drop_tool,
				  GUINT_TO_POINTER (device_info->device));
      gtk_table_attach (GTK_TABLE (deviceD->table), deviceD->tools[i],
			1, 2, i, i+1,
			0, 0, 2, 2);

      /*  the foreground color  */

      deviceD->foregrounds[i] = 
	gimp_color_area_new (&color,
			     GIMP_COLOR_AREA_FLAT,
			     GDK_BUTTON1_MASK | GDK_BUTTON2_MASK);
      gtk_widget_set_usize (deviceD->foregrounds[i], CELL_SIZE, CELL_SIZE);
      gtk_signal_connect (GTK_OBJECT (deviceD->foregrounds[i]), 
			  "color_changed",
			  GTK_SIGNAL_FUNC (device_status_foreground_changed),
			  GUINT_TO_POINTER (device_info->device));
      gtk_table_attach (GTK_TABLE (deviceD->table), 
			deviceD->foregrounds[i],
			2, 3, i, i+1,
			0, 0, 2, 2);

      /*  the background color  */

      deviceD->backgrounds[i] = 
	gimp_color_area_new (&color,
			     GIMP_COLOR_AREA_FLAT,
			     GDK_BUTTON1_MASK | GDK_BUTTON2_MASK);
      gtk_widget_set_usize (deviceD->backgrounds[i], CELL_SIZE, CELL_SIZE);
      gtk_signal_connect (GTK_OBJECT (deviceD->backgrounds[i]), 
			  "color_changed",
			  GTK_SIGNAL_FUNC (device_status_background_changed),
			  GUINT_TO_POINTER (device_info->device));
      gtk_table_attach (GTK_TABLE (deviceD->table), 
			deviceD->backgrounds[i],
			3, 4, i, i+1,
			0, 0, 2, 2);

      /*  the brush  */

      deviceD->brushes[i] =
	gimp_preview_new_full (GIMP_VIEWABLE (gimp_context_get_brush (device_info->context)),
			       CELL_SIZE, CELL_SIZE, 0,
			       FALSE, FALSE, TRUE);
      gtk_signal_connect_object_while_alive
	(GTK_OBJECT (device_info->context),
	 "brush_changed",
	 GTK_SIGNAL_FUNC (gimp_preview_set_viewable),
	 GTK_OBJECT (deviceD->brushes[i]));
      gimp_gtk_drag_dest_set_by_type (deviceD->brushes[i],
				      GTK_DEST_DEFAULT_ALL,
880
				      GIMP_TYPE_BRUSH,
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902
				      GDK_ACTION_COPY);
      gimp_dnd_viewable_dest_set (deviceD->brushes[i],
				  GIMP_TYPE_BRUSH,
				  device_status_drop_brush,
				  GUINT_TO_POINTER (device_info->device));
      gtk_table_attach (GTK_TABLE (deviceD->table), deviceD->brushes[i],
			4, 5, i, i+1,
			0, 0, 2, 2);

      /*  the pattern  */

      deviceD->patterns[i] =
	gimp_preview_new_full (GIMP_VIEWABLE (gimp_context_get_pattern (device_info->context)),
			       CELL_SIZE, CELL_SIZE, 0,
			       FALSE, FALSE, TRUE);
      gtk_signal_connect_object_while_alive
	(GTK_OBJECT (device_info->context),
	 "pattern_changed",
	 GTK_SIGNAL_FUNC (gimp_preview_set_viewable),
	 GTK_OBJECT (deviceD->patterns[i]));
      gimp_gtk_drag_dest_set_by_type (deviceD->patterns[i],
				      GTK_DEST_DEFAULT_ALL,
903
				      GIMP_TYPE_PATTERN,
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925
				      GDK_ACTION_COPY);
      gimp_dnd_viewable_dest_set (deviceD->patterns[i],
				  GIMP_TYPE_PATTERN,
				  device_status_drop_pattern,
				  GUINT_TO_POINTER (device_info->device));
      gtk_table_attach (GTK_TABLE(deviceD->table), deviceD->patterns[i],
			5, 6, i, i+1,
			0, 0, 2, 2);

      /*  the gradient  */

      deviceD->gradients[i] =
	gimp_preview_new_full (GIMP_VIEWABLE (gimp_context_get_gradient (device_info->context)),
			       CELL_SIZE * 2, CELL_SIZE, 0,
			       FALSE, FALSE, TRUE);
      gtk_signal_connect_object_while_alive
	(GTK_OBJECT (device_info->context),
	 "gradient_changed",
	 GTK_SIGNAL_FUNC (gimp_preview_set_viewable),
	 GTK_OBJECT (deviceD->gradients[i]));
      gimp_gtk_drag_dest_set_by_type (deviceD->gradients[i],
				      GTK_DEST_DEFAULT_ALL,
926
				      GIMP_TYPE_GRADIENT,
927 928 929 930 931 932 933 934 935 936 937
				      GDK_ACTION_COPY);
      gimp_dnd_viewable_dest_set (deviceD->gradients[i],
				  GIMP_TYPE_GRADIENT,
				  device_status_drop_gradient,
				  GUINT_TO_POINTER (device_info->device));
      gtk_table_attach (GTK_TABLE(deviceD->table), deviceD->gradients[i],
			6, 7, i, i+1,
			0, 0, 2, 2);

      device_status_update (device_info->device);
    }
Michael Natterer's avatar
Michael Natterer committed
938

939 940
  deviceD->current = 0xffffffff; /* random, but doesn't matter */
  device_status_update_current ();
941

942 943 944
  gtk_signal_connect (GTK_OBJECT (deviceD->shell), "destroy",
		      GTK_SIGNAL_FUNC (device_status_destroy_callback),
		      NULL);
945

946
  return deviceD->shell;
947 948 949 950 951
}

static void
device_status_destroy_callback (void)
{
952 953 954
  g_free (deviceD->ids);
  g_free (deviceD->frames);
  g_free (deviceD->tools);
955 956
  g_free (deviceD->foregrounds);
  g_free (deviceD->backgrounds);
957 958
  g_free (deviceD->brushes);
  g_free (deviceD->patterns);
Michael Natterer's avatar
Michael Natterer committed
959
  g_free (deviceD->gradients);
960 961

  g_free (deviceD);
962 963 964 965
  deviceD = NULL;
}

static void
966
devices_close_callback (GtkWidget *widget,
967
			gpointer   data)
968
{
969
  gtk_widget_hide (GTK_WIDGET (data));
970 971
}

972 973 974
void
device_status_free (void)
{                                     
Sven Neumann's avatar
Sven Neumann committed
975
  /* Save device status on exit */
976 977
  if (save_device_status)
    devices_write_rc ();
Sven Neumann's avatar
Sven Neumann committed
978

979
  if (deviceD)
980
    device_status_destroy_callback (); 
981 982
}

983
static void
984
device_status_update_current (void)
985
{
986
  gint i;
987 988 989

  if (deviceD)
    {
990
      for (i = 0; i < deviceD->num_devices; i++)
991 992 993 994 995 996 997 998
	{
	  if (deviceD->ids[i] == deviceD->current)
	    gtk_frame_set_shadow_type (GTK_FRAME(deviceD->frames[i]), 
				       GTK_SHADOW_OUT);
	  else if (deviceD->ids[i] == current_device)
	    gtk_frame_set_shadow_type (GTK_FRAME(deviceD->frames[i]), 
				       GTK_SHADOW_IN);
	}
999

1000 1001 1002 1003 1004 1005 1006 1007
      deviceD->current = current_device;
    }
}

void 
device_status_update (guint32 deviceid)
{
  GdkDeviceInfo *gdk_info;
1008
  DeviceInfo    *device_info;
1009
  GimpRGB        color;
1010
  guchar         red, green, blue;
1011 1012
  gchar          ttbuf[64];
  gint           i;
1013

1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
  if (!deviceD || suppress_update)
    return;

  if ((device_info = device_info_get_by_id (deviceid)) == NULL)
    return;

  if ((gdk_info = gdk_device_info_get_by_id (deviceid)) == NULL)
    return;

  for (i = 0; i < deviceD->num_devices; i++)
1024
    {
1025 1026 1027
      if (deviceD->ids[i] == deviceid)
	break;
    }
1028

1029
  g_return_if_fail (i < deviceD->num_devices);
1030

1031 1032 1033 1034
  if (gdk_info->mode == GDK_MODE_DISABLED)
    {
      gtk_widget_hide (deviceD->frames[i]);
      gtk_widget_hide (deviceD->tools[i]);
1035 1036
      gtk_widget_hide (deviceD->foregrounds[i]);
      gtk_widget_hide (deviceD->backgrounds[i]);
1037 1038
      gtk_widget_hide (deviceD->brushes[i]);
      gtk_widget_hide (deviceD->patterns[i]);
Michael Natterer's avatar
Michael Natterer committed
1039
      gtk_widget_hide (deviceD->gradients[i]);
1040 1041 1042 1043
    }
  else
    {
      gtk_widget_show (deviceD->frames[i]);
1044

1045 1046 1047 1048
      if (gimp_context_get_tool (device_info->context))
	{
	  gtk_widget_show (deviceD->tools[i]);
	}
1049

1050
      /*  foreground color  */
1051
      gimp_context_get_foreground (device_info->context, &color);
1052 1053 1054 1055
      gimp_color_area_set_color (GIMP_COLOR_AREA (deviceD->foregrounds[i]), 
				 &color);
      gtk_widget_show (deviceD->foregrounds[i]);

1056 1057 1058 1059
      /*  Set the tip to be the RGB value  */
      gimp_rgb_get_uchar (&color, &red, &green, &blue);
      g_snprintf (ttbuf, sizeof (ttbuf), _("Foreground: %d, %d, %d"),
		  red, green, blue);
1060 1061 1062 1063 1064 1065