gdkscreen.c 13.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * gdkscreen.c
 * 
 * Copyright 2001 Sun Microsystems Inc. 
 *
 * Erwann Chenede <erwann.chenede@sun.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

24
#include "config.h"
25

26
#include "gdkscreen.h"
27
#include "gdkinternals.h"
28 29 30

#include "gdkrectangle.h"
#include "gdkwindow.h"
31
#include "gdkintl.h"
32

33

34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/**
 * SECTION:gdkscreen
 * @Short_description: Object representing a physical screen
 * @Title: GdkScreen
 *
 * #GdkScreen objects are the GDK representation of a physical screen. It is used
 * throughout GDK and GTK+ to specify which screen the top level windows
 * are to be displayed on.
 * It is also used to query the screen specification and default settings such as
 * the screen width (gdk_screen_get_width()), etc.
 *
 * Note that a screen may consist of multiple monitors which are merged to
 * form a large screen area.
 */


50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
static void gdk_screen_finalize     (GObject        *object);
static void gdk_screen_set_property (GObject        *object,
				     guint           prop_id,
				     const GValue   *value,
				     GParamSpec     *pspec);
static void gdk_screen_get_property (GObject        *object,
				     guint           prop_id,
				     GValue         *value,
				     GParamSpec     *pspec);

enum
{
  PROP_0,
  PROP_FONT_OPTIONS,
  PROP_RESOLUTION
};
66 67 68 69

enum
{
  SIZE_CHANGED,
Søren Sandmann's avatar
Søren Sandmann committed
70
  COMPOSITED_CHANGED,
Søren Sandmann's avatar
Søren Sandmann committed
71
  MONITORS_CHANGED,
72 73 74 75 76
  LAST_SIGNAL
};

static guint signals[LAST_SIGNAL] = { 0 };

Matthias Clasen's avatar
Matthias Clasen committed
77
G_DEFINE_TYPE (GdkScreen, gdk_screen, G_TYPE_OBJECT)
78

Owen Taylor's avatar
Owen Taylor committed
79 80
static void
gdk_screen_class_init (GdkScreenClass *klass)
81
{
82 83
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

84
  object_class->finalize = gdk_screen_finalize;
85 86
  object_class->set_property = gdk_screen_set_property;
  object_class->get_property = gdk_screen_get_property;
87
  
88 89 90 91 92
  g_object_class_install_property (object_class,
				   PROP_FONT_OPTIONS,
				   g_param_spec_pointer ("font-options",
							 P_("Font options"),
							 P_("The default font options for the screen"),
Matthias Clasen's avatar
Matthias Clasen committed
93 94
							 G_PARAM_READWRITE|G_PARAM_STATIC_NAME|
							G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
95 96 97 98 99 100 101 102 103

  g_object_class_install_property (object_class,
				   PROP_RESOLUTION,
				   g_param_spec_double ("resolution",
							P_("Font resolution"),
							P_("The resolution for fonts on the screen"),
							-G_MAXDOUBLE,
							G_MAXDOUBLE,
							-1.0,
Matthias Clasen's avatar
Matthias Clasen committed
104 105
							G_PARAM_READWRITE|G_PARAM_STATIC_NAME|
							G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
106

107 108 109 110
  /**
   * GdkScreen::size-changed:
   * @screen: the object on which the signal is emitted
   * 
111
   * The ::size-changed signal is emitted when the pixel width or 
112 113 114 115
   * height of a screen changes.
   *
   * Since: 2.2
   */
116
  signals[SIZE_CHANGED] =
117
    g_signal_new (g_intern_static_string ("size-changed"),
118 119 120 121 122 123 124
                  G_OBJECT_CLASS_TYPE (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GdkScreenClass, size_changed),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE,
                  0);
Søren Sandmann's avatar
Søren Sandmann committed
125 126 127 128 129

  /**
   * GdkScreen::composited-changed:
   * @screen: the object on which the signal is emitted
   *
130
   * The ::composited-changed signal is emitted when the composited
Søren Sandmann's avatar
Søren Sandmann committed
131 132 133 134 135
   * status of the screen changes
   *
   * Since: 2.10
   */
  signals[COMPOSITED_CHANGED] =
136
    g_signal_new (g_intern_static_string ("composited-changed"),
Søren Sandmann's avatar
Søren Sandmann committed
137 138 139 140 141 142 143
		  G_OBJECT_CLASS_TYPE (klass),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkScreenClass, composited_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE,
		  0);
Søren Sandmann's avatar
Søren Sandmann committed
144 145 146 147 148
	
  /**
   * GdkScreen::monitors-changed:
   * @screen: the object on which the signal is emitted
   *
149
   * The ::monitors-changed signal is emitted when the number, size
Søren Sandmann's avatar
Søren Sandmann committed
150 151
   * or position of the monitors attached to the screen change. 
   *
152 153
   * Only for X11 and OS X for now. A future implementation for Win32
   * may be a possibility.
Søren Sandmann's avatar
Søren Sandmann committed
154 155 156 157
   *
   * Since: 2.14
   */
  signals[MONITORS_CHANGED] =
158
    g_signal_new (g_intern_static_string ("monitors-changed"),
Søren Sandmann's avatar
Søren Sandmann committed
159 160 161 162 163 164 165
		  G_OBJECT_CLASS_TYPE (klass),
		  G_SIGNAL_RUN_LAST,
		  G_STRUCT_OFFSET (GdkScreenClass, monitors_changed),
		  NULL, NULL,
		  g_cclosure_marshal_VOID__VOID,
		  G_TYPE_NONE,
		  0);
166 167
}

168 169 170
static void
gdk_screen_init (GdkScreen *screen)
{
171
  screen->resolution = -1.;
172 173 174 175 176 177 178 179 180 181
}

static void
gdk_screen_finalize (GObject *object)
{
  GdkScreen *screen = GDK_SCREEN (object);

  if (screen->font_options)
      cairo_font_options_destroy (screen->font_options);

Matthias Clasen's avatar
Matthias Clasen committed
182
  G_OBJECT_CLASS (gdk_screen_parent_class)->finalize (object);
183 184
}

185
void 
186
_gdk_screen_close (GdkScreen *screen)
187 188
{
  g_return_if_fail (GDK_IS_SCREEN (screen));
189 190 191 192 193 194

  if (!screen->closed)
    {
      screen->closed = TRUE;
      g_object_run_dispose (G_OBJECT (screen));
    }
195 196
}

197 198 199 200 201 202 203 204 205 206 207
/* Fallback used when the monitor "at" a point or window
 * doesn't exist.
 */
static gint
get_nearest_monitor (GdkScreen *screen,
		     gint       x,
		     gint       y)
{
  gint num_monitors, i;
  gint nearest_dist = G_MAXINT;
  gint nearest_monitor = 0;
Matthias Clasen's avatar
Matthias Clasen committed
208

209 210 211 212 213 214 215
  g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);

  num_monitors = gdk_screen_get_n_monitors (screen);
  
  for (i = 0; i < num_monitors; i++)
    {
      GdkRectangle monitor;
Matthias Clasen's avatar
Matthias Clasen committed
216
      gint dist_x, dist_y, dist;
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
      
      gdk_screen_get_monitor_geometry (screen, i, &monitor);

      if (x < monitor.x)
	dist_x = monitor.x - x;
      else if (x >= monitor.x + monitor.width)
	dist_x = x - (monitor.x + monitor.width) + 1;
      else
	dist_x = 0;

      if (y < monitor.y)
	dist_y = monitor.y - y;
      else if (y >= monitor.y + monitor.height)
	dist_y = y - (monitor.y + monitor.height) + 1;
      else
	dist_y = 0;

Matthias Clasen's avatar
Matthias Clasen committed
234 235
      dist = dist_x + dist_y;
      if (dist < nearest_dist)
236
	{
Matthias Clasen's avatar
Matthias Clasen committed
237
	  nearest_dist = dist;
238 239 240 241 242 243 244
	  nearest_monitor = i;
	}
    }

  return nearest_monitor;
}

245 246
/**
 * gdk_screen_get_monitor_at_point:
Matthias Clasen's avatar
Matthias Clasen committed
247 248 249
 * @screen: a #GdkScreen.
 * @x: the x coordinate in the virtual screen.
 * @y: the y coordinate in the virtual screen.
250 251 252
 *
 * Returns the monitor number in which the point (@x,@y) is located.
 *
253 254
 * Returns: the monitor number in which the point (@x,@y) lies, or
 *   a monitor close to (@x,@y) if the point is not in any monitor.
Matthias Clasen's avatar
Matthias Clasen committed
255 256
 *
 * Since: 2.2
257 258 259 260 261 262
 **/
gint 
gdk_screen_get_monitor_at_point (GdkScreen *screen,
				 gint       x,
				 gint       y)
{
263 264
  gint num_monitors, i;
  
265
  g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
266 267

  num_monitors = gdk_screen_get_n_monitors (screen);
268
  
269 270 271 272 273 274 275 276 277 278 279 280 281
  for (i=0;i<num_monitors;i++)
    {
      GdkRectangle monitor;
      
      gdk_screen_get_monitor_geometry (screen, i, &monitor);

      if (x >= monitor.x &&
          x < monitor.x + monitor.width &&
          y >= monitor.y &&
          y < (monitor.y + monitor.height))
        return i;
    }

282
  return get_nearest_monitor (screen, x, y);
283 284 285
}

/**
Matthias Clasen's avatar
Matthias Clasen committed
286 287 288
 * gdk_screen_get_monitor_at_window:
 * @screen: a #GdkScreen.
 * @window: a #GdkWindow
289 290 291
 * @returns: the monitor number in which most of @window is located,
 *           or if @window does not intersect any monitors, a monitor,
 *           close to @window.
292
 *
Matthias Clasen's avatar
Matthias Clasen committed
293
 * Returns the number of the monitor in which the largest area of the 
294
 * bounding rectangle of @window resides.
Matthias Clasen's avatar
Matthias Clasen committed
295 296
 *
 * Since: 2.2
297 298 299
 **/
gint 
gdk_screen_get_monitor_at_window (GdkScreen      *screen,
300
				  GdkWindow	 *window)
301
{
302
  gint num_monitors, i, area = 0, screen_num = -1;
303
  GdkRectangle win_rect;
304

305
  g_return_val_if_fail (GDK_IS_SCREEN (screen), -1);
306

307
  gdk_window_get_geometry (window, &win_rect.x, &win_rect.y, &win_rect.width,
308
			   &win_rect.height);
309 310 311 312 313 314 315 316 317 318
  gdk_window_get_origin (window, &win_rect.x, &win_rect.y);
  num_monitors = gdk_screen_get_n_monitors (screen);
  
  for (i=0;i<num_monitors;i++)
    {
      GdkRectangle tmp_monitor, intersect;
      
      gdk_screen_get_monitor_geometry (screen, i, &tmp_monitor);
      gdk_rectangle_intersect (&win_rect, &tmp_monitor, &intersect);
      
319
      if (intersect.width * intersect.height > area)
320
	{ 
321
	  area = intersect.width * intersect.height;
322 323 324
	  screen_num = i;
	}
    }
325 326 327 328 329 330
  if (screen_num >= 0)
    return screen_num;
  else
    return get_nearest_monitor (screen,
				win_rect.x + win_rect.width / 2,
				win_rect.y + win_rect.height / 2);
331
}
332 333 334 335 336 337

/**
 * gdk_screen_width:
 * 
 * Returns the width of the default screen in pixels.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
338
 * Return value: the width of the default screen in pixels.
339 340 341 342
 **/
gint
gdk_screen_width (void)
{
343
  return gdk_screen_get_width (gdk_screen_get_default ());
344 345 346 347 348 349 350 351 352 353 354 355
}

/**
 * gdk_screen_height:
 * 
 * Returns the height of the default screen in pixels.
 * 
 * Return value: the height of the default screen in pixels.
 **/
gint
gdk_screen_height (void)
{
356
  return gdk_screen_get_height (gdk_screen_get_default ());
357 358 359 360 361 362 363 364 365 366 367 368 369 370
}

/**
 * gdk_screen_width_mm:
 * 
 * Returns the width of the default screen in millimeters.
 * Note that on many X servers this value will not be correct.
 * 
 * Return value: the width of the default screen in millimeters,
 * though it is not always correct.
 **/
gint
gdk_screen_width_mm (void)
{
371
  return gdk_screen_get_width_mm (gdk_screen_get_default ());
372 373 374 375 376 377 378 379 380 381 382 383 384 385
}

/**
 * gdk_screen_height_mm:
 * 
 * Returns the height of the default screen in millimeters.
 * Note that on many X servers this value will not be correct.
 * 
 * Return value: the height of the default screen in millimeters,
 * though it is not always correct.
 **/
gint
gdk_screen_height_mm (void)
{
Owen Taylor's avatar
Owen Taylor committed
386
  return gdk_screen_get_height_mm (gdk_screen_get_default ());
387
}
388

389
/**
390
 * gdk_screen_set_font_options:
391
 * @screen: a #GdkScreen
Johan Dahlin's avatar
Johan Dahlin committed
392
 * @options: (allow-none): a #cairo_font_options_t, or %NULL to unset any
393 394 395 396 397 398 399
 *   previously set default font options.
 *
 * Sets the default font options for the screen. These
 * options will be set on any #PangoContext's newly created
 * with gdk_pango_context_get_for_screen(). Changing the
 * default set of font options does not affect contexts that
 * have already been created.
400 401
 *
 * Since: 2.10
402 403
 **/
void
404 405
gdk_screen_set_font_options (GdkScreen                  *screen,
			     const cairo_font_options_t *options)
406
{
407
  g_return_if_fail (GDK_IS_SCREEN (screen));
408

409 410 411 412 413 414 415 416 417 418 419 420
  if (screen->font_options != options)
    {
      if (screen->font_options)
        cairo_font_options_destroy (screen->font_options);

      if (options)
        screen->font_options = cairo_font_options_copy (options);
      else
        screen->font_options = NULL;

      g_object_notify (G_OBJECT (screen), "font-options");
    }
421 422 423
}

/**
424
 * gdk_screen_get_font_options:
425 426
 * @screen: a #GdkScreen
 * 
427
 * Gets any options previously set with gdk_screen_set_font_options().
428 429 430
 * 
 * Return value: the current font options, or %NULL if no default
 *  font options have been set.
431 432
 *
 * Since: 2.10
433 434
 **/
const cairo_font_options_t *
435
gdk_screen_get_font_options (GdkScreen *screen)
436
{
437
  g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
438

439
  return screen->font_options;
440 441 442
}

/**
443
 * gdk_screen_set_resolution:
444 445 446 447 448 449 450 451 452
 * @screen: a #GdkScreen
 * @dpi: the resolution in "dots per inch". (Physical inches aren't actually
 *   involved; the terminology is conventional.)
 
 * Sets the resolution for font handling on the screen. This is a
 * scale factor between points specified in a #PangoFontDescription
 * and cairo units. The default value is 96, meaning that a 10 point
 * font will be 13 units high. (10 * 96. / 72. = 13.3).
 *
453
 * Since: 2.10
454 455
 **/
void
456 457
gdk_screen_set_resolution (GdkScreen *screen,
			   gdouble    dpi)
458
{
459
  g_return_if_fail (GDK_IS_SCREEN (screen));
460

461 462
  if (dpi < 0)
    dpi = -1.0;
463

464 465 466
  if (screen->resolution != dpi)
    {
      screen->resolution = dpi;
467

468 469
      g_object_notify (G_OBJECT (screen), "resolution");
    }
470 471 472
}

/**
473
 * gdk_screen_get_resolution:
474 475 476
 * @screen: a #GdkScreen
 * 
 * Gets the resolution for font handling on the screen; see
477
 * gdk_screen_set_resolution() for full details.
478 479 480
 * 
 * Return value: the current resolution, or -1 if no resolution
 * has been set.
481 482
 *
 * Since: 2.10
483 484
 **/
gdouble
485
gdk_screen_get_resolution (GdkScreen *screen)
486
{
487
  g_return_val_if_fail (GDK_IS_SCREEN (screen), -1.0);
488

489
  return screen->resolution;
490 491
}

492 493 494 495 496 497 498 499 500 501 502
static void
gdk_screen_get_property (GObject      *object,
			 guint         prop_id,
			 GValue       *value,
			 GParamSpec   *pspec)
{
  GdkScreen *screen = GDK_SCREEN (object);

  switch (prop_id)
    {
    case PROP_FONT_OPTIONS:
503
      g_value_set_pointer (value, (gpointer) gdk_screen_get_font_options (screen));
504 505 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
      break;
    case PROP_RESOLUTION:
      g_value_set_double (value, gdk_screen_get_resolution (screen));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gdk_screen_set_property (GObject      *object,
			 guint         prop_id,
			 const GValue *value,
			 GParamSpec   *pspec)
{
  GdkScreen *screen = GDK_SCREEN (object);

  switch (prop_id)
    {
    case PROP_FONT_OPTIONS:
      gdk_screen_set_font_options (screen, g_value_get_pointer (value));
      break;
    case PROP_RESOLUTION:
      gdk_screen_set_resolution (screen, g_value_get_double (value));
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}