gdkgc-x11.c 22.3 KB
Newer Older
1 2 3 4
/* GDK - The GIMP Drawing Kit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6 7 8 9 10 11
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15 16 17 18 19 20
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
21
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22 23 24 25 26
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

27 28
#include <config.h>

29
#include "gdkgc.h"
30
#include "gdkprivate-x11.h"
31
#include "gdkregion-generic.h"
32
#include "gdkx.h"
33

34 35
#include <string.h>

36 37 38 39
typedef enum {
  GDK_GC_DIRTY_CLIP = 1 << 0,
  GDK_GC_DIRTY_TS = 1 << 1
} GdkGCDirtyValues;
40 41 42 43

static void gdk_x11_gc_values_to_xvalues (GdkGCValues    *values,
					  GdkGCValuesMask mask,
					  XGCValues      *xvalues,
44
					  unsigned long  *xvalues_mask);
45

46 47 48 49 50 51 52
static void gdk_x11_gc_get_values (GdkGC           *gc,
				   GdkGCValues     *values);
static void gdk_x11_gc_set_values (GdkGC           *gc,
				   GdkGCValues     *values,
				   GdkGCValuesMask  values_mask);
static void gdk_x11_gc_set_dashes (GdkGC           *gc,
				   gint             dash_offset,
53
				   gint8            dash_list[],
54 55
				   gint             n);

56 57 58 59 60 61
static void gdk_gc_x11_class_init (GdkGCX11Class *klass);
static void gdk_gc_x11_finalize   (GObject           *object);

static gpointer parent_class = NULL;

GType
62
_gdk_gc_x11_get_type (void)
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
{
  static GType object_type = 0;

  if (!object_type)
    {
      static const GTypeInfo object_info =
      {
        sizeof (GdkGCX11Class),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) gdk_gc_x11_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (GdkGCX11),
        0,              /* n_preallocs */
        (GInstanceInitFunc) NULL,
      };
      
      object_type = g_type_register_static (GDK_TYPE_GC,
                                            "GdkGCX11",
83
                                            &object_info, 0);
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    }
  
  return object_type;
}

static void
gdk_gc_x11_class_init (GdkGCX11Class *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  GdkGCClass *gc_class = GDK_GC_CLASS (klass);
  
  parent_class = g_type_class_peek_parent (klass);

  object_class->finalize = gdk_gc_x11_finalize;

  gc_class->get_values = gdk_x11_gc_get_values;
  gc_class->set_values = gdk_x11_gc_set_values;
  gc_class->set_dashes = gdk_x11_gc_set_dashes;
}

static void
gdk_gc_x11_finalize (GObject *object)
{
  GdkGCX11 *x11_gc = GDK_GC_X11 (object);
  
  if (x11_gc->clip_region)
    gdk_region_destroy (x11_gc->clip_region);
  
112
#if HAVE_XFT
113
  if (x11_gc->fg_picture != None)
114
    XRenderFreePicture (GDK_GC_XDISPLAY (x11_gc), x11_gc->fg_picture);
115
#endif  
116
  
117 118
  XFreeGC (GDK_GC_XDISPLAY (x11_gc), GDK_GC_XGC (x11_gc));

119 120 121
  G_OBJECT_CLASS (parent_class)->finalize (object);
}

122 123 124 125 126 127 128

GdkGC *
_gdk_x11_gc_new (GdkDrawable      *drawable,
		 GdkGCValues      *values,
		 GdkGCValuesMask   values_mask)
{
  GdkGC *gc;
129
  GdkGCX11 *private;
130 131 132 133
  
  XGCValues xvalues;
  unsigned long xvalues_mask;

134 135 136 137
  /* NOTICE that the drawable here has to be the impl drawable,
   * not the publically-visible drawables.
   */
  g_return_val_if_fail (GDK_IS_DRAWABLE_IMPL_X11 (drawable), NULL);
138

139
  gc = g_object_new (_gdk_gc_x11_get_type (), NULL);
140
  private = GDK_GC_X11 (gc);
141

142
  private->dirty_mask = 0;
143
  private->have_clip_mask = FALSE;
144
  private->clip_region = NULL;
145
    
146
  private->screen = GDK_DRAWABLE_IMPL_X11 (drawable)->screen;
147

148 149 150
  if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
    {
      values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
151
      private->dirty_mask |= GDK_GC_DIRTY_CLIP;
152 153 154 155 156
    }

  if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
    {
      values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
157
      private->dirty_mask |= GDK_GC_DIRTY_TS;
158 159
    }

160 161
  if (values_mask & GDK_GC_FOREGROUND)
    private->fg_pixel = values->foreground.pixel;
162 163 164 165

  if ((values_mask & GDK_GC_CLIP_MASK) && values->clip_mask)
    private->have_clip_mask = TRUE;

166 167 168 169
  xvalues.function = GXcopy;
  xvalues.fill_style = FillSolid;
  xvalues.arc_mode = ArcPieSlice;
  xvalues.subwindow_mode = ClipByChildren;
170
  xvalues.graphics_exposures = False;
171 172
  xvalues_mask = GCFunction | GCFillStyle | GCArcMode | GCSubwindowMode | GCGraphicsExposures;

173
  gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
174
  
175 176 177
  private->xgc = XCreateGC (GDK_GC_XDISPLAY (gc),
                            GDK_DRAWABLE_IMPL_X11 (drawable)->xid,
                            xvalues_mask, &xvalues);
178 179 180 181

  return gc;
}

182 183 184
GC
_gdk_x11_gc_flush (GdkGC *gc)
{
185
  GdkGCX11 *private = GDK_GC_X11 (gc);
186

187
  if (private->dirty_mask & GDK_GC_DIRTY_CLIP)
188
    {
189
      if (!private->clip_region)
190
	XSetClipOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
191
			gc->clip_x_origin, gc->clip_y_origin);
192 193
      else
	{
194 195 196 197 198 199 200 201
	  XRectangle *rectangles;
          gint n_rects;

          _gdk_region_get_xrectangles (private->clip_region,
                                       gc->clip_x_origin,
                                       gc->clip_y_origin,
                                       &rectangles,
                                       &n_rects);
202
	  
203 204 205 206
	  XSetClipRectangles (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), 0, 0,
                              rectangles,
                              n_rects, YXBanded);
          
207 208 209 210
	  g_free (rectangles);
	}
    }

211
  if (private->dirty_mask & GDK_GC_DIRTY_TS)
212 213
    {
      XSetTSOrigin (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
214
		    gc->ts_x_origin, gc->ts_y_origin);
215 216
    }

217
  private->dirty_mask = 0;
218 219 220
  return GDK_GC_XGC (gc);
}

221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
static void
gdk_x11_gc_get_values (GdkGC       *gc,
		       GdkGCValues *values)
{
  XGCValues xvalues;
  
  if (XGetGCValues (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
		    GCForeground | GCBackground | GCFont |
		    GCFunction | GCTile | GCStipple | /* GCClipMask | */
		    GCSubwindowMode | GCGraphicsExposures |
		    GCTileStipXOrigin | GCTileStipYOrigin |
		    GCClipXOrigin | GCClipYOrigin |
		    GCLineWidth | GCLineStyle | GCCapStyle |
		    GCFillStyle | GCJoinStyle, &xvalues))
    {
      values->foreground.pixel = xvalues.foreground;
      values->background.pixel = xvalues.background;
238 239
      values->font = gdk_font_lookup_for_display (GDK_GC_DISPLAY (gc),
						  xvalues.font);
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 274 275 276 277 278 279 280 281 282 283 284 285 286 287

      switch (xvalues.function)
	{
	case GXcopy:
	  values->function = GDK_COPY;
	  break;
	case GXinvert:
	  values->function = GDK_INVERT;
	  break;
	case GXxor:
	  values->function = GDK_XOR;
	  break;
	case GXclear:
	  values->function = GDK_CLEAR;
	  break;
	case GXand:
	  values->function = GDK_AND;
	  break;
	case GXandReverse:
	  values->function = GDK_AND_REVERSE;
	  break;
	case GXandInverted:
	  values->function = GDK_AND_INVERT;
	  break;
	case GXnoop:
	  values->function = GDK_NOOP;
	  break;
	case GXor:
	  values->function = GDK_OR;
	  break;
	case GXequiv:
	  values->function = GDK_EQUIV;
	  break;
	case GXorReverse:
	  values->function = GDK_OR_REVERSE;
	  break;
	case GXcopyInverted:
	  values->function =GDK_COPY_INVERT;
	  break;
	case GXorInverted:
	  values->function = GDK_OR_INVERT;
	  break;
	case GXnand:
	  values->function = GDK_NAND;
	  break;
	case GXset:
	  values->function = GDK_SET;
	  break;
Elliot Lee's avatar
Elliot Lee committed
288 289 290
	case GXnor:
	  values->function = GDK_NOR;
	  break;
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	}

      switch (xvalues.fill_style)
	{
	case FillSolid:
	  values->fill = GDK_SOLID;
	  break;
	case FillTiled:
	  values->fill = GDK_TILED;
	  break;
	case FillStippled:
	  values->fill = GDK_STIPPLED;
	  break;
	case FillOpaqueStippled:
	  values->fill = GDK_OPAQUE_STIPPLED;
	  break;
	}

309 310 311 312
      values->tile = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
						    xvalues.tile);
      values->stipple = gdk_pixmap_lookup_for_display (GDK_GC_DISPLAY (gc),
						       xvalues.stipple);
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375
      values->clip_mask = NULL;
      values->subwindow_mode = xvalues.subwindow_mode;
      values->ts_x_origin = xvalues.ts_x_origin;
      values->ts_y_origin = xvalues.ts_y_origin;
      values->clip_x_origin = xvalues.clip_x_origin;
      values->clip_y_origin = xvalues.clip_y_origin;
      values->graphics_exposures = xvalues.graphics_exposures;
      values->line_width = xvalues.line_width;

      switch (xvalues.line_style)
	{
	case LineSolid:
	  values->line_style = GDK_LINE_SOLID;
	  break;
	case LineOnOffDash:
	  values->line_style = GDK_LINE_ON_OFF_DASH;
	  break;
	case LineDoubleDash:
	  values->line_style = GDK_LINE_DOUBLE_DASH;
	  break;
	}

      switch (xvalues.cap_style)
	{
	case CapNotLast:
	  values->cap_style = GDK_CAP_NOT_LAST;
	  break;
	case CapButt:
	  values->cap_style = GDK_CAP_BUTT;
	  break;
	case CapRound:
	  values->cap_style = GDK_CAP_ROUND;
	  break;
	case CapProjecting:
	  values->cap_style = GDK_CAP_PROJECTING;
	  break;
	}

      switch (xvalues.join_style)
	{
	case JoinMiter:
	  values->join_style = GDK_JOIN_MITER;
	  break;
	case JoinRound:
	  values->join_style = GDK_JOIN_ROUND;
	  break;
	case JoinBevel:
	  values->join_style = GDK_JOIN_BEVEL;
	  break;
	}
    }
  else
    {
      memset (values, 0, sizeof (GdkGCValues));
    }
}


static void
gdk_x11_gc_set_values (GdkGC           *gc,
		       GdkGCValues     *values,
		       GdkGCValuesMask  values_mask)
{
376
  GdkGCX11 *x11_gc;
377 378 379
  XGCValues xvalues;
  unsigned long xvalues_mask = 0;

380
  x11_gc = GDK_GC_X11 (gc);
381 382 383 384

  if (values_mask & (GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN))
    {
      values_mask &= ~(GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN);
385
      x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
386 387 388 389 390
    }

  if (values_mask & (GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN))
    {
      values_mask &= ~(GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN);
391
      x11_gc->dirty_mask |= GDK_GC_DIRTY_TS;
392 393 394 395
    }

  if (values_mask & GDK_GC_CLIP_MASK)
    {
396
      if (x11_gc->clip_region)
397
	{
398 399
	  gdk_region_destroy (x11_gc->clip_region);
	  x11_gc->clip_region = NULL;
400
	}
401 402

      x11_gc->have_clip_mask = values->clip_mask != NULL;
403 404
    }

405 406 407
  if (values_mask & GDK_GC_FOREGROUND)
    x11_gc->fg_pixel = values->foreground.pixel;
  
408
  gdk_x11_gc_values_to_xvalues (values, values_mask, &xvalues, &xvalues_mask);
409 410 411 412 413 414 415 416 417 418

  XChangeGC (GDK_GC_XDISPLAY (gc),
	     GDK_GC_XGC (gc),
	     xvalues_mask,
	     &xvalues);
}

static void
gdk_x11_gc_set_dashes (GdkGC *gc,
		       gint   dash_offset,
419
		       gint8  dash_list[],
420 421
		       gint   n)
{
422
  g_return_if_fail (GDK_IS_GC (gc));
423 424 425 426 427 428 429 430 431 432
  g_return_if_fail (dash_list != NULL);

  XSetDashes (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc),
	      dash_offset, dash_list, n);
}

static void
gdk_x11_gc_values_to_xvalues (GdkGCValues    *values,
			      GdkGCValuesMask mask,
			      XGCValues      *xvalues,
433
			      unsigned long  *xvalues_mask)
434
{
435
  /* Optimization for the common case (gdk_gc_new()) */
436
  if (values == NULL || mask == 0)
437 438
    return;
  
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
  if (mask & GDK_GC_FOREGROUND)
    {
      xvalues->foreground = values->foreground.pixel;
      *xvalues_mask |= GCForeground;
    }
  if (mask & GDK_GC_BACKGROUND)
    {
      xvalues->background = values->background.pixel;
      *xvalues_mask |= GCBackground;
    }
  if ((mask & GDK_GC_FONT) && (values->font->type == GDK_FONT_FONT))
    {
      xvalues->font = ((XFontStruct *) (GDK_FONT_XFONT (values->font)))->fid;
      *xvalues_mask |= GCFont;
    }
  if (mask & GDK_GC_FUNCTION)
    {
      switch (values->function)
	{
	case GDK_COPY:
	  xvalues->function = GXcopy;
	  break;
	case GDK_INVERT:
	  xvalues->function = GXinvert;
	  break;
	case GDK_XOR:
	  xvalues->function = GXxor;
	  break;
	case GDK_CLEAR:
	  xvalues->function = GXclear;
	  break;
	case GDK_AND:
	  xvalues->function = GXand;
	  break;
	case GDK_AND_REVERSE:
	  xvalues->function = GXandReverse;
	  break;
	case GDK_AND_INVERT:
	  xvalues->function = GXandInverted;
	  break;
	case GDK_NOOP:
	  xvalues->function = GXnoop;
	  break;
	case GDK_OR:
	  xvalues->function = GXor;
	  break;
	case GDK_EQUIV:
	  xvalues->function = GXequiv;
	  break;
	case GDK_OR_REVERSE:
	  xvalues->function = GXorReverse;
	  break;
	case GDK_COPY_INVERT:
	  xvalues->function = GXcopyInverted;
	  break;
	case GDK_OR_INVERT:
	  xvalues->function = GXorInverted;
	  break;
	case GDK_NAND:
	  xvalues->function = GXnand;
	  break;
	case GDK_SET:
	  xvalues->function = GXset;
	  break;
Elliot Lee's avatar
Elliot Lee committed
503 504 505
	case GDK_NOR:
	  xvalues->function = GXnor;
	  break;
506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 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 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
	}
      *xvalues_mask |= GCFunction;
    }
  if (mask & GDK_GC_FILL)
    {
      switch (values->fill)
	{
	case GDK_SOLID:
	  xvalues->fill_style = FillSolid;
	  break;
	case GDK_TILED:
	  xvalues->fill_style = FillTiled;
	  break;
	case GDK_STIPPLED:
	  xvalues->fill_style = FillStippled;
	  break;
	case GDK_OPAQUE_STIPPLED:
	  xvalues->fill_style = FillOpaqueStippled;
	  break;
	}
      *xvalues_mask |= GCFillStyle;
    }
  if (mask & GDK_GC_TILE)
    {
      if (values->tile)
	xvalues->tile = GDK_DRAWABLE_XID (values->tile);
      else
	xvalues->tile = None;
      
      *xvalues_mask |= GCTile;
    }
  if (mask & GDK_GC_STIPPLE)
    {
      if (values->stipple)
	xvalues->stipple = GDK_DRAWABLE_XID (values->stipple);
      else
	xvalues->stipple = None;
      
      *xvalues_mask |= GCStipple;
    }
  if (mask & GDK_GC_CLIP_MASK)
    {
      if (values->clip_mask)
	xvalues->clip_mask = GDK_DRAWABLE_XID (values->clip_mask);
      else
	xvalues->clip_mask = None;

      *xvalues_mask |= GCClipMask;
      
    }
  if (mask & GDK_GC_SUBWINDOW)
    {
      xvalues->subwindow_mode = values->subwindow_mode;
      *xvalues_mask |= GCSubwindowMode;
    }
  if (mask & GDK_GC_TS_X_ORIGIN)
    {
      xvalues->ts_x_origin = values->ts_x_origin;
      *xvalues_mask |= GCTileStipXOrigin;
    }
  if (mask & GDK_GC_TS_Y_ORIGIN)
    {
      xvalues->ts_y_origin = values->ts_y_origin;
      *xvalues_mask |= GCTileStipYOrigin;
    }
  if (mask & GDK_GC_CLIP_X_ORIGIN)
    {
      xvalues->clip_x_origin = values->clip_x_origin;
      *xvalues_mask |= GCClipXOrigin;
    }
  if (mask & GDK_GC_CLIP_Y_ORIGIN)
    {
      xvalues->clip_y_origin = values->clip_y_origin;
      *xvalues_mask |= GCClipYOrigin;
    }

  if (mask & GDK_GC_EXPOSURES)
583 584 585 586
    {
      xvalues->graphics_exposures = values->graphics_exposures;
      *xvalues_mask |= GCGraphicsExposures;
    }
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650

  if (mask & GDK_GC_LINE_WIDTH)
    {
      xvalues->line_width = values->line_width;
      *xvalues_mask |= GCLineWidth;
    }
  if (mask & GDK_GC_LINE_STYLE)
    {
      switch (values->line_style)
	{
	case GDK_LINE_SOLID:
	  xvalues->line_style = LineSolid;
	  break;
	case GDK_LINE_ON_OFF_DASH:
	  xvalues->line_style = LineOnOffDash;
	  break;
	case GDK_LINE_DOUBLE_DASH:
	  xvalues->line_style = LineDoubleDash;
	  break;
	}
      *xvalues_mask |= GCLineStyle;
    }
  if (mask & GDK_GC_CAP_STYLE)
    {
      switch (values->cap_style)
	{
	case GDK_CAP_NOT_LAST:
	  xvalues->cap_style = CapNotLast;
	  break;
	case GDK_CAP_BUTT:
	  xvalues->cap_style = CapButt;
	  break;
	case GDK_CAP_ROUND:
	  xvalues->cap_style = CapRound;
	  break;
	case GDK_CAP_PROJECTING:
	  xvalues->cap_style = CapProjecting;
	  break;
	}
      *xvalues_mask |= GCCapStyle;
    }
  if (mask & GDK_GC_JOIN_STYLE)
    {
      switch (values->join_style)
	{
	case GDK_JOIN_MITER:
	  xvalues->join_style = JoinMiter;
	  break;
	case GDK_JOIN_ROUND:
	  xvalues->join_style = JoinRound;
	  break;
	case GDK_JOIN_BEVEL:
	  xvalues->join_style = JoinBevel;
	  break;
	}
      *xvalues_mask |= GCJoinStyle;
    }

}

void
gdk_gc_set_clip_rectangle (GdkGC	*gc,
			   GdkRectangle *rectangle)
{
651
  GdkGCX11 *x11_gc;
652 653
  gboolean had_region = FALSE;
  
654
  g_return_if_fail (GDK_IS_GC (gc));
655

656
  x11_gc = GDK_GC_X11 (gc);
657

658
  if (x11_gc->clip_region)
659 660 661 662
    {
      had_region = TRUE;
      gdk_region_destroy (x11_gc->clip_region);
    }
663

664
  if (rectangle)
665
    x11_gc->clip_region = gdk_region_rectangle (rectangle);
666
  else
667 668 669 670 671 672
    x11_gc->clip_region = NULL;

  /* Unset immediately, to make sure Xlib doesn't keep the
   * XID of an old clip mask cached
   */
  if ((had_region && !rectangle) || x11_gc->have_clip_mask)
673
    {
674
      XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
675
      x11_gc->have_clip_mask = FALSE;
676
    }
677

678 679
  gc->clip_x_origin = 0;
  gc->clip_y_origin = 0;
680
  
681
  x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
Havoc Pennington's avatar
Havoc Pennington committed
682
}
683 684

void
685 686
gdk_gc_set_clip_region (GdkGC	  *gc,
			GdkRegion *region)
687
{
688
  GdkGCX11 *x11_gc;
689
  gboolean had_region = FALSE;
690

691
  g_return_if_fail (GDK_IS_GC (gc));
692

693
  x11_gc = GDK_GC_X11 (gc);
694

695
  if (x11_gc->clip_region)
696 697 698 699
    {
      had_region = TRUE;
      gdk_region_destroy (x11_gc->clip_region);
    }
700 701

  if (region)
702
    x11_gc->clip_region = gdk_region_copy (region);
703
  else
704 705 706 707 708 709
    x11_gc->clip_region = NULL;    

  /* Unset immediately, to make sure Xlib doesn't keep the
   * XID of an old clip mask cached
   */
  if ((had_region && !region) || x11_gc->have_clip_mask)
710
    {
711
      XSetClipMask (GDK_GC_XDISPLAY (gc), GDK_GC_XGC (gc), None);
712
      x11_gc->have_clip_mask = FALSE;
713
    }
714

715 716
  gc->clip_x_origin = 0;
  gc->clip_y_origin = 0;
717
  
718
  x11_gc->dirty_mask |= GDK_GC_DIRTY_CLIP;
719 720 721 722 723 724
}


void
gdk_gc_copy (GdkGC *dst_gc, GdkGC *src_gc)
{
Havoc Pennington's avatar
Havoc Pennington committed
725 726 727
  GdkGCX11 *x11_src_gc;
  GdkGCX11 *x11_dst_gc;
  
728 729
  g_return_if_fail (GDK_IS_GC_X11 (dst_gc));
  g_return_if_fail (GDK_IS_GC_X11 (src_gc));
Havoc Pennington's avatar
Havoc Pennington committed
730 731 732

  x11_dst_gc = GDK_GC_X11 (dst_gc);
  x11_src_gc = GDK_GC_X11 (src_gc);
733 734 735
  
  XCopyGC (GDK_GC_XDISPLAY (src_gc), GDK_GC_XGC (src_gc), ~((~1) << GCLastBit),
	   GDK_GC_XGC (dst_gc));
Havoc Pennington's avatar
Havoc Pennington committed
736 737 738 739 740 741 742

  dst_gc->clip_x_origin = src_gc->clip_x_origin;
  dst_gc->clip_y_origin = src_gc->clip_y_origin;
  dst_gc->ts_x_origin = src_gc->ts_x_origin;
  dst_gc->ts_y_origin = src_gc->ts_y_origin;

  if (src_gc->colormap)
743
    g_object_ref (src_gc->colormap);
Havoc Pennington's avatar
Havoc Pennington committed
744 745

  if (dst_gc->colormap)
746
    g_object_unref (dst_gc->colormap);
Havoc Pennington's avatar
Havoc Pennington committed
747 748 749 750 751 752

  dst_gc->colormap = src_gc->colormap;

  if (x11_dst_gc->clip_region)
    gdk_region_destroy (x11_dst_gc->clip_region);

753 754 755 756
  if (x11_src_gc->clip_region)
    x11_dst_gc->clip_region = gdk_region_copy (x11_src_gc->clip_region);
  else
    x11_dst_gc->clip_region = NULL;
Havoc Pennington's avatar
Havoc Pennington committed
757 758

  x11_dst_gc->dirty_mask = x11_src_gc->dirty_mask;
759
  x11_dst_gc->fg_pixel = x11_src_gc->fg_pixel;
760
}
761

762 763 764 765 766 767 768
/**
 * gdk_gc_get_screen:
 * @gc: a #GdkGC.
 *
 * Gets the #GdkScreen for which @gc was created
 *
 * Returns: the #GdkScreen for @gc.
Matthias Clasen's avatar
Matthias Clasen committed
769 770
 *
 * Since: 2.2
771 772 773 774 775 776 777 778 779
 */
GdkScreen *  
gdk_gc_get_screen (GdkGC *gc)
{
  g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);
  
  return GDK_GC_X11 (gc)->screen;
}

Matthias Clasen's avatar
Matthias Clasen committed
780 781 782 783 784 785 786 787
/**
 * gdk_x11_gc_get_xdisplay:
 * @gc: a #GdkGC.
 * 
 * Returns the display of a #GdkGC.
 * 
 * Return value: an Xlib <type>Display*</type>.
 **/
788 789 790 791 792
Display *
gdk_x11_gc_get_xdisplay (GdkGC *gc)
{
  g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);

793
  return GDK_SCREEN_XDISPLAY (gdk_gc_get_screen (gc));
794 795
}

Matthias Clasen's avatar
Matthias Clasen committed
796 797 798 799 800 801 802 803
/**
 * gdk_x11_gc_get_xgc:
 * @gc: a #GdkGC.
 * 
 * Returns the X GC of a #GdkGC.
 * 
 * Return value: an Xlib <type>GC</type>.
 **/
804 805 806 807 808 809 810 811 812 813 814 815 816 817
GC
gdk_x11_gc_get_xgc (GdkGC *gc)
{
  GdkGCX11 *gc_x11;
  
  g_return_val_if_fail (GDK_IS_GC_X11 (gc), NULL);

  gc_x11 = GDK_GC_X11 (gc);

  if (gc_x11->dirty_mask)
    _gdk_x11_gc_flush (gc);

  return gc_x11->xgc;
}
818

Owen Taylor's avatar
Owen Taylor committed
819
#ifdef HAVE_XFT
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 852 853 854 855 856 857 858 859 860 861 862
/* Various bits of the below are roughly cribbed from XFree86
 * lib/Xft/xftdraw.c, Copyright 2000, Keith Packard
 */

static XRenderPictFormat *
foreground_format (GdkGC *gc)
{
  XRenderPictFormat pf;

  pf.type = PictTypeDirect;
  pf.depth = 32;
  pf.direct.redMask = 0xff;
  pf.direct.greenMask = 0xff;
  pf.direct.blueMask = 0xff;
  pf.direct.alphaMask = 0xff;

  return XRenderFindFormat (GDK_GC_XDISPLAY (gc),
			    (PictFormatType |
			     PictFormatDepth |
			     PictFormatRedMask |
			     PictFormatGreenMask |
			     PictFormatBlueMask |
			     PictFormatAlphaMask),
			    &pf,
			    0);
}

/**
 * _gdk_x11_gc_get_fg_picture:
 * @gc: a #GdkGC
 * 
 * Gets a Xrender Picture object suitable for being the source
 * drawable for drawing with the foreground the graphics context.
 * (Currently, only foreground color is handled, but in the
 * future we should handle tiles/stipples as well.)
 * 
 * Return value: a Picture, owned by the GC; this cannot be
 *   used over subsequent modification of the GC.
 **/
Picture
_gdk_x11_gc_get_fg_picture (GdkGC *gc)
{
  GdkGCX11 *x11_gc;
863
  GdkColormap *cmap;
864 865 866 867 868
  gboolean new = FALSE;
  GdkColor color;
  
  g_return_val_if_fail (GDK_IS_GC_X11 (gc), None);

869
  if (!_gdk_x11_have_render (GDK_GC_DISPLAY (gc)))
870 871
    return None;

872
  x11_gc = GDK_GC_X11 (gc);
873
  cmap = gdk_gc_get_colormap (gc);
874 875 876 877 878

  if (x11_gc->fg_picture == None)
    {
      XRenderPictureAttributes pa;
      XRenderPictFormat *pix_format = foreground_format (gc);
879
      Pixmap pix;
880

881 882 883
      if (!pix_format)
	return None;

884 885
      pix = XCreatePixmap (GDK_GC_XDISPLAY (gc), 
			   GDK_SCREEN_XROOTWIN (x11_gc->screen),
886
			   1, 1, pix_format->depth);
887
      pa.repeat = True;
888
      x11_gc->fg_picture = XRenderCreatePicture (GDK_GC_XDISPLAY (gc), 
889 890 891
						 pix,
						 pix_format,
						 CPRepeat, &pa);
892
      XFreePixmap (GDK_GC_XDISPLAY (gc), pix);
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
      
      new = TRUE;
    }

  gdk_colormap_query_color (cmap, x11_gc->fg_pixel, &color);

  if (new ||
      x11_gc->fg_picture_color.red != color.red ||
      x11_gc->fg_picture_color.green != color.green ||
      x11_gc->fg_picture_color.blue != color.blue)
    {
      x11_gc->fg_picture_color.red = color.red;
      x11_gc->fg_picture_color.green = color.green;
      x11_gc->fg_picture_color.blue = color.blue;
      x11_gc->fg_picture_color.alpha = 0xffff;

909
      XRenderFillRectangle (GDK_GC_XDISPLAY (gc), PictOpSrc, 
910 911 912 913 914 915
			    x11_gc->fg_picture, &x11_gc->fg_picture_color,
			    0, 0, 1, 1); 
    }

  return x11_gc->fg_picture;
}
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945

/**
 * _gdk_gc_x11_get_fg_xft_color:
 * @gc: a #GdkGC
 * @xftcolor: location to store the color
 * 
 * Gets the foreground color of the GC as a XftColor.
 **/
void
_gdk_gc_x11_get_fg_xft_color (GdkGC    *gc,
			      XftColor *xftcolor)
{
  GdkGCX11 *x11_gc;
  GdkColormap *cmap;
  GdkColor color;
  
  g_return_if_fail (GDK_IS_GC_X11 (gc));

  x11_gc = GDK_GC_X11 (gc);
  cmap = gdk_gc_get_colormap (gc);

  xftcolor->pixel = x11_gc->fg_pixel;

  gdk_colormap_query_color (cmap, xftcolor->pixel, &color);
  xftcolor->color.red = color.red;
  xftcolor->color.green = color.green;
  xftcolor->color.blue = color.blue;
  xftcolor->color.alpha = 0xffff;
}

946
#endif /* HAVE_XFT */