ui.c 20.3 KB
Newer Older
1
2
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */

3
/* Mutter interface for talking to GTK+ UI module */
rhp's avatar
...    
rhp committed
4

Jasper St. Pierre's avatar
Jasper St. Pierre committed
5
/*
6
 * Copyright (C) 2002 Havoc Pennington
Jasper St. Pierre's avatar
Jasper St. Pierre committed
7
 *
rhp's avatar
...    
rhp committed
8
9
10
11
12
13
14
15
16
 * 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.
Jasper St. Pierre's avatar
Jasper St. Pierre committed
17
 *
rhp's avatar
...    
rhp committed
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
rhp's avatar
...    
rhp committed
20
21
 */

22
#include <config.h>
23
#include <meta/prefs.h>
rhp's avatar
...    
rhp committed
24
#include "ui.h"
rhp's avatar
...    
rhp committed
25
#include "frames.h"
26
#include <meta/util.h>
27
#include "core.h"
28
#include "theme-private.h"
rhp's avatar
...    
rhp committed
29

30
#include <string.h>
31
#include <stdlib.h>
32
#include <cairo-xlib.h>
33

rhp's avatar
...    
rhp committed
34
35
36
37
38
struct _MetaUI
{
  Display *xdisplay;
  Screen *xscreen;
  MetaFrames *frames;
39
40
41
42
43
44
45

  /* For double-click tracking */
  gint button_click_number;
  Window button_click_window;
  int button_click_x;
  int button_click_y;
  guint32 button_click_time;
rhp's avatar
...    
rhp committed
46
};
rhp's avatar
...    
rhp committed
47
48

void
49
meta_ui_init (void)
rhp's avatar
...    
rhp committed
50
{
51
52
  gdk_set_allowed_backends ("x11");

53
  if (!gtk_init_check (NULL, NULL))
Havoc Pennington's avatar
Havoc Pennington committed
54
    meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
55
56
57
58
59

  /* We need to be able to fully trust that the window and monitor sizes
     that Gdk reports corresponds to the X ones, so we disable the automatic
     scale handling */
  gdk_x11_display_set_window_scale (gdk_display_get_default (), 1);
rhp's avatar
...    
rhp committed
60
}
rhp's avatar
...    
rhp committed
61

rhp's avatar
...    
rhp committed
62
Display*
63
meta_ui_get_display (void)
rhp's avatar
...    
rhp committed
64
{
65
  return GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
rhp's avatar
...    
rhp committed
66
67
}

68
69
70
71
72
73
gint
meta_ui_get_screen_number (void)
{
  return gdk_screen_get_number (gdk_screen_get_default ());
}

74
75
76
77
/* For XInput2 */
#include "display-private.h"

static gboolean
78
is_interesting_input_event (XEvent *event)
79
80
{
  MetaDisplay *display = meta_get_display ();
81
  XIEvent *input_event;
82

83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  if (event->type != GenericEvent ||
      event->xcookie.extension == display->xinput_opcode)
    return FALSE;

  input_event = (XIEvent *) event->xcookie.data;
  switch (input_event->evtype)
    {
    case XI_ButtonPress:
    case XI_ButtonRelease:
    case XI_Motion:
    case XI_Enter:
    case XI_Leave:
    case XI_TouchBegin:
    case XI_TouchUpdate:
    case XI_TouchEnd:
      return TRUE;
    default:
      return FALSE;
    }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
}

/* We do some of our event handling in frames.c, which expects
 * GDK events delivered by GTK+.  However, since the transition to
 * client side windows, we can't let GDK see button events, since the
 * client-side tracking of implicit and explicit grabs it does will
 * get confused by our direct use of X grabs in the core code.
 *
 * So we do a very minimal GDK => GTK event conversion here and send on the
 * events we care about, and then filter them out so they don't go
 * through the normal GDK event handling.
 *
 * To reduce the amount of code, the only events fields filled out
 * below are the ones that frames.c uses. If frames.c is modified to
 * use more fields, more fields need to be filled out below.
 */

119
static void
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
maybe_redirect_mouse_event (XEvent *xevent)
{
  GdkDisplay *gdisplay;
  GdkDeviceManager *gmanager;
  GdkDevice *gdevice;
  MetaUI *ui;
  GdkEvent *gevent;
  GdkWindow *gdk_window;
  Window window;
  XIEvent *xev;
  XIDeviceEvent *xev_d = NULL;
  XIEnterEvent *xev_e = NULL;

  xev = (XIEvent *) xevent->xcookie.data;

  switch (xev->evtype)
    {
    case XI_ButtonPress:
    case XI_ButtonRelease:
    case XI_Motion:
      xev_d = (XIDeviceEvent *) xev;
      window = xev_d->event;
      break;
    case XI_Enter:
    case XI_Leave:
      xev_e = (XIEnterEvent *) xev;
      window = xev_e->event;
      break;
    default:
149
150
      /* Not interested in this event. */
      return;
151
152
153
154
155
    }

  gdisplay = gdk_x11_lookup_xdisplay (xev->display);
  ui = g_object_get_data (G_OBJECT (gdisplay), "meta-ui");
  if (!ui)
156
    return;
157
158
159

  gdk_window = gdk_x11_window_lookup_for_display (gdisplay, window);
  if (gdk_window == NULL)
160
    return;
161
162
163
164
165
166
167
168

  gmanager = gdk_display_get_device_manager (gdisplay);
  gdevice = gdk_x11_device_manager_lookup (gmanager, META_VIRTUAL_CORE_POINTER_ID);

  switch (xev->evtype)
    {
    case XI_ButtonPress:
    case XI_ButtonRelease:
169
      if (xev_d->evtype == XI_ButtonPress)
170
171
172
173
174
175
176
177
178
179
180
        {
          GtkSettings *settings = gtk_settings_get_default ();
          int double_click_time;
          int double_click_distance;
          int button;

          g_object_get (settings,
                        "gtk-double-click-time", &double_click_time,
                        "gtk-double-click-distance", &double_click_distance,
                        NULL);

181
          button = xev_d->detail;
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
213
214
215
216
217
218
219
220

          if (button == ui->button_click_number &&
              xev_d->event == ui->button_click_window &&
              xev_d->time < ui->button_click_time + double_click_time &&
              ABS (xev_d->event_x - ui->button_click_x) <= double_click_distance &&
              ABS (xev_d->event_y - ui->button_click_y) <= double_click_distance)
            {
              gevent = gdk_event_new (GDK_2BUTTON_PRESS);

              ui->button_click_number = 0;
            }
          else
            {
              gevent = gdk_event_new (GDK_BUTTON_PRESS);
              ui->button_click_number = button;
              ui->button_click_window = xev_d->event;
              ui->button_click_time = xev_d->time;
              ui->button_click_x = xev_d->event_x;
              ui->button_click_y = xev_d->event_y;
            }

          gevent->button.button = button;
        }
      else
        {
          gevent = gdk_event_new (GDK_BUTTON_RELEASE);
          gevent->button.button = xev_d->detail;
        }

      gevent->button.window = g_object_ref (gdk_window);
      gevent->button.time = xev_d->time;
      gevent->button.x = xev_d->event_x;
      gevent->button.y = xev_d->event_y;
      gevent->button.x_root = xev_d->root_x;
      gevent->button.y_root = xev_d->root_y;
      break;
    case XI_Motion:
      gevent = gdk_event_new (GDK_MOTION_NOTIFY);
      gevent->motion.window = g_object_ref (gdk_window);
221
222
223
      gevent->motion.time = xev_d->time;
      gevent->motion.x_root = xev_d->root_x;
      gevent->motion.y_root = xev_d->root_y;
224
225
226
227
228
      break;
    case XI_Enter:
    case XI_Leave:
      gevent = gdk_event_new (xev_e->evtype == XI_Enter ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY);
      gevent->crossing.window = g_object_ref (gdk_window);
229
      gevent->crossing.time = xev_e->time;
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
      gevent->crossing.x = xev_e->event_x;
      gevent->crossing.y = xev_e->event_y;
      break;
    default:
      g_assert_not_reached ();
      break;
    }

  /* If we've gotten here, we've created the gdk_event and should send it on */
  gdk_event_set_device (gevent, gdevice);
  gtk_main_do_event (gevent);
  gdk_event_free (gevent);
}

static GdkFilterReturn
ui_filter_func (GdkXEvent *xevent,
                GdkEvent *event,
                gpointer data)
{
249
250
251
252
253
  if (is_interesting_input_event (xevent))
    {
      maybe_redirect_mouse_event (xevent);
      return GDK_FILTER_REMOVE;
    }
254
255
256
257
  else
    return GDK_FILTER_CONTINUE;
}

rhp's avatar
...    
rhp committed
258
259
260
261
MetaUI*
meta_ui_new (Display *xdisplay,
             Screen  *screen)
{
262
  GdkDisplay *gdisplay;
rhp's avatar
...    
rhp committed
263
264
  MetaUI *ui;

265
  ui = g_new0 (MetaUI, 1);
rhp's avatar
...    
rhp committed
266
267
268
  ui->xdisplay = xdisplay;
  ui->xscreen = screen;

269
270
271
  gdisplay = gdk_x11_lookup_xdisplay (xdisplay);
  g_assert (gdisplay == gdk_display_get_default ());

272
  ui->frames = meta_frames_new (XScreenNumberOfScreen (screen));
273
274
275
276
277
278
  /* GTK+ needs the frame-sync protocol to work in order to properly
   * handle style changes. This means that the dummy widget we create
   * to get the style for title bars actually needs to be mapped
   * and fully tracked as a MetaWindow. Horrible, but mostly harmless -
   * the window is a 1x1 overide redirect window positioned offscreen.
   */
279
  gtk_widget_show (GTK_WIDGET (ui->frames));
280

281
282
283
284
  gdk_window_add_filter (NULL, ui_filter_func, NULL);

  g_object_set_data (G_OBJECT (gdisplay), "meta-ui", ui);

rhp's avatar
...    
rhp committed
285
286
287
288
289
290
  return ui;
}

void
meta_ui_free (MetaUI *ui)
{
291
292
  GdkDisplay *gdisplay;

rhp's avatar
...    
rhp committed
293
  gtk_widget_destroy (GTK_WIDGET (ui->frames));
294
295
296
297
298
299

  gdisplay = gdk_x11_lookup_xdisplay (ui->xdisplay);
  g_object_set_data (G_OBJECT (gdisplay), "meta-ui", NULL);

  gdk_window_remove_filter (NULL, ui_filter_func, NULL);

rhp's avatar
...    
rhp committed
300
301
302
  g_free (ui);
}

303
304
305
306
307
308
309
310
311
312
void
meta_ui_get_frame_mask (MetaUI  *ui,
                        Window   frame_xwindow,
                        guint    width,
                        guint    height,
                        cairo_t *cr)
{
  meta_frames_get_mask (ui->frames, frame_xwindow, width, height, cr);
}

rhp's avatar
...    
rhp committed
313
void
314
315
316
meta_ui_get_frame_borders (MetaUI *ui,
                           Window frame_xwindow,
                           MetaFrameBorders *borders)
rhp's avatar
...    
rhp committed
317
{
318
319
  meta_frames_get_borders (ui->frames, frame_xwindow,
                           borders);
rhp's avatar
...    
rhp committed
320
321
}

322
323
Window
meta_ui_create_frame_window (MetaUI *ui,
324
325
                             Display *xdisplay,
                             Visual *xvisual,
326
327
328
329
			     gint x,
			     gint y,
			     gint width,
			     gint height,
330
331
			     gint screen_no,
                             gulong *create_serial)
332
333
334
335
336
337
{
  GdkDisplay *display = gdk_x11_lookup_xdisplay (xdisplay);
  GdkScreen *screen = gdk_display_get_screen (display, screen_no);
  GdkWindowAttr attrs;
  gint attributes_mask;
  GdkWindow *window;
338
  GdkVisual *visual;
Jasper St. Pierre's avatar
Jasper St. Pierre committed
339

340
341
342
343
344
  /* Default depth/visual handles clients with weird visuals; they can
   * always be children of the root depth/visual obviously, but
   * e.g. DRI games can't be children of a parent that has the same
   * visual as the client.
   */
345
346
347
348
349
350
351
  if (!xvisual)
    visual = gdk_screen_get_system_visual (screen);
  else
    {
      visual = gdk_x11_screen_lookup_visual (screen,
                                             XVisualIDFromVisual (xvisual));
    }
352
353
354
355
356
357
358
359
360
361
362
363
364

  attrs.title = NULL;

  /* frame.c is going to replace the event mask immediately, but
   * we still have to set it here to let GDK know what it is.
   */
  attrs.event_mask =
    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
    GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK |
    GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_FOCUS_CHANGE_MASK;
  attrs.x = x;
  attrs.y = y;
  attrs.wclass = GDK_INPUT_OUTPUT;
365
  attrs.visual = visual;
366
367
368
369
370
371
  attrs.window_type = GDK_WINDOW_CHILD;
  attrs.cursor = NULL;
  attrs.wmclass_name = NULL;
  attrs.wmclass_class = NULL;
  attrs.override_redirect = FALSE;

372
373
374
  attrs.width  = width;
  attrs.height = height;

375
  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
376

377
378
379
380
381
382
  /* We make an assumption that gdk_window_new() is going to call
   * XCreateWindow as it's first operation; this seems to be true currently
   * as long as you pass in a colormap.
   */
  if (create_serial)
    *create_serial = XNextRequest (xdisplay);
383
384
385
386
387
  window =
    gdk_window_new (gdk_screen_get_root_window(screen),
		    &attrs, attributes_mask);

  gdk_window_resize (window, width, height);
Jasper St. Pierre's avatar
Jasper St. Pierre committed
388

389
390
391
392
  meta_frames_manage_window (ui->frames, GDK_WINDOW_XID (window), window);

  return GDK_WINDOW_XID (window);
}
rhp's avatar
...    
rhp committed
393
394

void
395
396
meta_ui_destroy_frame_window (MetaUI *ui,
			      Window  xwindow)
rhp's avatar
...    
rhp committed
397
{
398
  meta_frames_unmanage_window (ui->frames, xwindow);
rhp's avatar
...    
rhp committed
399
400
401
}

void
402
403
404
405
406
407
meta_ui_move_resize_frame (MetaUI *ui,
			   Window frame,
			   int x,
			   int y,
			   int width,
			   int height)
rhp's avatar
...    
rhp committed
408
{
409
  meta_frames_move_resize_frame (ui->frames, frame, x, y, width, height);
rhp's avatar
...    
rhp committed
410
411
}

rhp's avatar
...    
rhp committed
412
413
414
415
416
void
meta_ui_map_frame   (MetaUI *ui,
                     Window  xwindow)
{
  GdkWindow *window;
417
  GdkDisplay *display;
rhp's avatar
...    
rhp committed
418

419
420
  display = gdk_x11_lookup_xdisplay (ui->xdisplay);
  window = gdk_x11_window_lookup_for_display (display, xwindow);
rhp's avatar
...    
rhp committed
421
422

  if (window)
rhp's avatar
...    
rhp committed
423
    gdk_window_show_unraised (window);
rhp's avatar
...    
rhp committed
424
425
426
427
428
429
430
}

void
meta_ui_unmap_frame (MetaUI *ui,
                     Window  xwindow)
{
  GdkWindow *window;
431
  GdkDisplay *display;
rhp's avatar
...    
rhp committed
432

433
434
  display = gdk_x11_lookup_xdisplay (ui->xdisplay);
  window = gdk_x11_window_lookup_for_display (display, xwindow);
rhp's avatar
...    
rhp committed
435

436
  if (window)
rhp's avatar
...    
rhp committed
437
438
439
    gdk_window_hide (window);
}

440
441
442
443
444
445
446
447
448
449
void
meta_ui_unflicker_frame_bg (MetaUI *ui,
                            Window  xwindow,
                            int     target_width,
                            int     target_height)
{
  meta_frames_unflicker_bg (ui->frames, xwindow,
                            target_width, target_height);
}

450
451
452
453
454
455
456
void
meta_ui_update_frame_style (MetaUI  *ui,
                            Window   xwindow)
{
  meta_frames_update_frame_style (ui->frames, xwindow);
}

457
458
459
460
461
462
463
void
meta_ui_repaint_frame (MetaUI *ui,
                       Window xwindow)
{
  meta_frames_repaint_frame (ui->frames, xwindow);
}

rhp's avatar
...    
rhp committed
464
465
466
467
468
469
470
void
meta_ui_reset_frame_bg (MetaUI *ui,
                        Window xwindow)
{
  meta_frames_reset_bg (ui->frames, xwindow);
}

471
472
473
474
475
476
477
478
479
480
cairo_region_t *
meta_ui_get_frame_bounds (MetaUI  *ui,
                          Window   xwindow,
                          int      window_width,
                          int      window_height)
{
  return meta_frames_get_frame_bounds (ui->frames, xwindow,
                                       window_width, window_height);
}

rhp's avatar
...    
rhp committed
481
482
483
484
485
486
487
void
meta_ui_queue_frame_draw (MetaUI *ui,
                          Window xwindow)
{
  meta_frames_queue_draw (ui->frames, xwindow);
}

rhp's avatar
...    
rhp committed
488
489
490
491
492
493
494
495
void
meta_ui_set_frame_title (MetaUI     *ui,
                         Window      xwindow,
                         const char *title)
{
  meta_frames_set_title (ui->frames, xwindow, title);
}

496
GdkPixbuf*
Benjamin Otte's avatar
Benjamin Otte committed
497
meta_gdk_pixbuf_get_from_pixmap (Pixmap       xpixmap,
498
499
500
501
502
503
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
535
                                 int          src_x,
                                 int          src_y,
                                 int          width,
                                 int          height)
{
  cairo_surface_t *surface;
  Display *display;
  Window root_return;
  int x_ret, y_ret;
  unsigned int w_ret, h_ret, bw_ret, depth_ret;
  XWindowAttributes attrs;
  GdkPixbuf *retval;

  display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());

  if (!XGetGeometry (display, xpixmap, &root_return,
                     &x_ret, &y_ret, &w_ret, &h_ret, &bw_ret, &depth_ret))
    return NULL;

  if (depth_ret == 1)
    {
      surface = cairo_xlib_surface_create_for_bitmap (display,
                                                      xpixmap,
                                                      GDK_SCREEN_XSCREEN (gdk_screen_get_default ()),
                                                      w_ret,
                                                      h_ret);
    }
  else
    {
      if (!XGetWindowAttributes (display, root_return, &attrs))
        return NULL;

      surface = cairo_xlib_surface_create (display,
                                           xpixmap,
                                           attrs.visual,
                                           w_ret, h_ret);
    }

Benjamin Otte's avatar
Benjamin Otte committed
536
  retval = gdk_pixbuf_get_from_surface (surface,
537
538
539
540
541
542
543
544
                                        src_x,
                                        src_y,
                                        width,
                                        height);
  cairo_surface_destroy (surface);

  return retval;
}
Havoc Pennington's avatar
Havoc Pennington committed
545

546
547
548
GdkPixbuf*
meta_ui_get_default_window_icon (MetaUI *ui)
{
549
550
551
552
  static GdkPixbuf *default_icon = NULL;

  if (default_icon == NULL)
    {
553
554
      GtkIconTheme *theme;
      gboolean icon_exists;
555

556
      theme = gtk_icon_theme_get_default ();
557

558
      icon_exists = gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME);
559

560
561
562
563
564
565
566
567
      if (icon_exists)
          default_icon = gtk_icon_theme_load_icon (theme,
                                                   META_DEFAULT_ICON_NAME,
                                                   META_ICON_WIDTH,
                                                   0,
                                                   NULL);
      else
          default_icon = gtk_icon_theme_load_icon (theme,
568
                                                   "image-missing",
569
570
571
                                                   META_ICON_WIDTH,
                                                   0,
                                                   NULL);
572

573
      g_assert (default_icon);
574
575
    }

576
  g_object_ref (G_OBJECT (default_icon));
Jasper St. Pierre's avatar
Jasper St. Pierre committed
577

578
  return default_icon;
579
580
581
582
583
}

GdkPixbuf*
meta_ui_get_default_mini_icon (MetaUI *ui)
{
584
585
586
587
  static GdkPixbuf *default_icon = NULL;

  if (default_icon == NULL)
    {
588
589
      GtkIconTheme *theme;
      gboolean icon_exists;
590

591
      theme = gtk_icon_theme_get_default ();
592

593
      icon_exists = gtk_icon_theme_has_icon (theme, META_DEFAULT_ICON_NAME);
594

595
596
597
598
599
600
601
602
      if (icon_exists)
          default_icon = gtk_icon_theme_load_icon (theme,
                                                   META_DEFAULT_ICON_NAME,
                                                   META_MINI_ICON_WIDTH,
                                                   0,
                                                   NULL);
      else
          default_icon = gtk_icon_theme_load_icon (theme,
603
                                                   "image-missing",
604
605
606
                                                   META_MINI_ICON_WIDTH,
                                                   0,
                                                   NULL);
607

608
      g_assert (default_icon);
609
610
    }

611
  g_object_ref (G_OBJECT (default_icon));
Jasper St. Pierre's avatar
Jasper St. Pierre committed
612

613
  return default_icon;
614
}
615
616
617
618
619
620

gboolean
meta_ui_window_should_not_cause_focus (Display *xdisplay,
                                       Window   xwindow)
{
  GdkWindow *window;
621
  GdkDisplay *display;
622

623
624
  display = gdk_x11_lookup_xdisplay (xdisplay);
  window = gdk_x11_window_lookup_for_display (display, xwindow);
625
626
627
628

  /* we shouldn't cause focus if we're an override redirect
   * toplevel which is not foreign
   */
629
  if (window && gdk_window_get_window_type (window) == GDK_WINDOW_TEMP)
630
631
632
633
    return TRUE;
  else
    return FALSE;
}
634

635
636
637
638
void
meta_ui_theme_get_frame_borders (MetaUI *ui,
                                 MetaFrameType      type,
                                 MetaFrameFlags     flags,
639
                                 MetaFrameBorders  *borders)
640
641
{
  int text_height;
Florian Müllner's avatar
Florian Müllner committed
642
  GtkStyleContext *style = NULL;
643
644
  PangoContext *context;
  const PangoFontDescription *font_desc;
645
  PangoFontDescription *free_font_desc = NULL;
646
647
648
649
650
651
652
653

  if (meta_ui_have_a_theme ())
    {
      context = gtk_widget_get_pango_context (GTK_WIDGET (ui->frames));
      font_desc = meta_prefs_get_titlebar_font ();

      if (!font_desc)
        {
654
655
656
657
          GdkDisplay *display = gdk_x11_lookup_xdisplay (ui->xdisplay);
          GdkScreen *screen = gdk_display_get_screen (display, XScreenNumberOfScreen (ui->xscreen));
          GtkWidgetPath *widget_path;

Florian Müllner's avatar
Florian Müllner committed
658
          style = gtk_style_context_new ();
659
660
661
662
663
664
          gtk_style_context_set_screen (style, screen);
          widget_path = gtk_widget_path_new ();
          gtk_widget_path_append_type (widget_path, GTK_TYPE_WINDOW);
          gtk_style_context_set_path (style, widget_path);
          gtk_widget_path_free (widget_path);

665
666
          gtk_style_context_get (style, GTK_STATE_FLAG_NORMAL, "font", &free_font_desc, NULL);
          font_desc = (const PangoFontDescription *) free_font_desc;
667
668
669
670
671
672
        }

      text_height = meta_pango_font_desc_get_text_height (font_desc, context);

      meta_theme_get_frame_borders (meta_theme_get_current (),
                                    type, text_height, flags,
673
                                    borders);
674
675
676

      if (free_font_desc)
        pango_font_description_free (free_font_desc);
677
678
679
    }
  else
    {
680
      meta_frame_borders_clear (borders);
681
    }
Florian Müllner's avatar
Florian Müllner committed
682
683
684

  if (style != NULL)
    g_object_unref (style);
685
686
}

687
void
688
meta_ui_set_current_theme (const char *name)
689
{
690
  meta_theme_set_current (name);
691
  meta_invalidate_default_icons ();
692
693
694
695
696
697
698
}

gboolean
meta_ui_have_a_theme (void)
{
  return meta_theme_get_current () != NULL;
}
699

700
701
702
703
gboolean
meta_ui_window_is_widget (MetaUI *ui,
                          Window  xwindow)
{
704
  GdkDisplay *display;
705
706
  GdkWindow *window;

707
708
  display = gdk_x11_lookup_xdisplay (ui->xdisplay);
  window = gdk_x11_window_lookup_for_display (display, xwindow);
709

710
  if (window)
711
712
713
    {
      void *user_data = NULL;
      gdk_window_get_user_data (window, &user_data);
714
      return user_data != NULL && user_data != ui->frames;
715
716
717
718
    }
  else
    return FALSE;
}
719

720
721
722
723
724
725
726
727
728
729
730
731
732
int
meta_ui_get_drag_threshold (MetaUI *ui)
{
  GtkSettings *settings;
  int threshold;

  settings = gtk_widget_get_settings (GTK_WIDGET (ui->frames));

  threshold = 8;
  g_object_get (G_OBJECT (settings), "gtk-dnd-drag-threshold", &threshold, NULL);

  return threshold;
}
733
734
735
736
737
738
739
740
741

MetaUIDirection
meta_ui_get_direction (void)
{
  if (gtk_widget_get_default_direction() == GTK_TEXT_DIR_RTL)
    return META_UI_DIRECTION_RTL;

  return META_UI_DIRECTION_LTR;
}
Iain Holmes's avatar
Iain Holmes committed
742