~osomon/unity-2d/metacity-respect-launcher

« back to all changes in this revision

Viewing changes to .pc/15_show_maximized_titlebars.patch/src/ui/frames.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2011-01-19 13:20:50 UTC
  • Revision ID: james.westby@ubuntu.com-20110119132050-haxwdq0d7o8nlnc4
Tags: 1:2.30.3-0ubuntu3
* debian/patches/15_show_maximized_titlebars.patch:
  needed to make decorations work properly with the new unity-2d
* debian/control:
  add Breaks: entry to libmetacity-private0 for the current compiz version,
  since we need a compiz rebuild for the new ABI

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
 
 
3
/* Metacity window frame manager widget */
 
4
 
 
5
/* 
 
6
 * Copyright (C) 2001 Havoc Pennington
 
7
 * Copyright (C) 2003 Red Hat, Inc.
 
8
 * Copyright (C) 2005, 2006 Elijah Newren
 
9
 * 
 
10
 * This program is free software; you can redistribute it and/or
 
11
 * modify it under the terms of the GNU General Public License as
 
12
 * published by the Free Software Foundation; either version 2 of the
 
13
 * License, or (at your option) any later version.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful, but
 
16
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
 * General Public License for more details.
 
19
 * 
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with this program; if not, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
23
 * 02111-1307, USA.
 
24
 */
 
25
 
 
26
#include <config.h>
 
27
#include <math.h>
 
28
#include "boxes.h"
 
29
#include "frames.h"
 
30
#include "util.h"
 
31
#include "core.h"
 
32
#include "menu.h"
 
33
#include "fixedtip.h"
 
34
#include "theme.h"
 
35
#include "prefs.h"
 
36
#include "ui.h"
 
37
 
 
38
#ifdef HAVE_SHAPE
 
39
#include <X11/extensions/shape.h>
 
40
#endif
 
41
 
 
42
#define DEFAULT_INNER_BUTTON_BORDER 3
 
43
 
 
44
static void meta_frames_class_init (MetaFramesClass *klass);
 
45
static void meta_frames_init       (MetaFrames      *frames);
 
46
static void meta_frames_destroy    (GtkObject       *object);
 
47
static void meta_frames_finalize   (GObject         *object);
 
48
static void meta_frames_style_set  (GtkWidget       *widget,
 
49
                                    GtkStyle        *prev_style);
 
50
static void meta_frames_realize    (GtkWidget       *widget);
 
51
static void meta_frames_unrealize  (GtkWidget       *widget);
 
52
 
 
53
static void meta_frames_update_prelit_control (MetaFrames      *frames,
 
54
                                               MetaUIFrame     *frame,
 
55
                                               MetaFrameControl control);
 
56
static gboolean meta_frames_button_press_event    (GtkWidget           *widget,
 
57
                                                   GdkEventButton      *event);
 
58
static gboolean meta_frames_button_release_event  (GtkWidget           *widget,
 
59
                                                   GdkEventButton      *event);
 
60
static gboolean meta_frames_motion_notify_event   (GtkWidget           *widget,
 
61
                                                   GdkEventMotion      *event);
 
62
static gboolean meta_frames_destroy_event         (GtkWidget           *widget,
 
63
                                                   GdkEventAny         *event);
 
64
static gboolean meta_frames_expose_event          (GtkWidget           *widget,
 
65
                                                   GdkEventExpose      *event);
 
66
static gboolean meta_frames_enter_notify_event    (GtkWidget           *widget,
 
67
                                                   GdkEventCrossing    *event);
 
68
static gboolean meta_frames_leave_notify_event    (GtkWidget           *widget,
 
69
                                                   GdkEventCrossing    *event);
 
70
 
 
71
static void meta_frames_attach_style (MetaFrames  *frames,
 
72
                                      MetaUIFrame *frame);
 
73
 
 
74
static void meta_frames_paint_to_drawable (MetaFrames   *frames,
 
75
                                           MetaUIFrame  *frame,
 
76
                                           GdkDrawable  *drawable,
 
77
                                           GdkRegion    *region,
 
78
                                           int           x_offset,
 
79
                                           int           y_offset);
 
80
 
 
81
static void meta_frames_set_window_background (MetaFrames   *frames,
 
82
                                               MetaUIFrame  *frame);
 
83
 
 
84
static void meta_frames_calc_geometry (MetaFrames        *frames,
 
85
                                       MetaUIFrame         *frame,
 
86
                                       MetaFrameGeometry *fgeom);
 
87
 
 
88
static void meta_frames_ensure_layout (MetaFrames      *frames,
 
89
                                       MetaUIFrame     *frame);
 
90
 
 
91
static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
 
92
                                               Window      xwindow);
 
93
 
 
94
static void meta_frames_font_changed          (MetaFrames *frames);
 
95
static void meta_frames_button_layout_changed (MetaFrames *frames);
 
96
 
 
97
 
 
98
static GdkRectangle*    control_rect (MetaFrameControl   control,
 
99
                                      MetaFrameGeometry *fgeom);
 
100
static MetaFrameControl get_control  (MetaFrames        *frames,
 
101
                                      MetaUIFrame       *frame,
 
102
                                      int                x,
 
103
                                      int                y);
 
104
static void clear_tip (MetaFrames *frames);
 
105
static void invalidate_all_caches (MetaFrames *frames);
 
106
static void invalidate_whole_window (MetaFrames *frames,
 
107
                                     MetaUIFrame *frame);
 
108
 
 
109
static GtkWidgetClass *parent_class = NULL;
 
110
 
 
111
GType
 
112
meta_frames_get_type (void)
 
113
{
 
114
  static GType frames_type = 0;
 
115
 
 
116
  if (!frames_type)
 
117
    {
 
118
      static const GtkTypeInfo frames_info =
 
119
      {
 
120
        "MetaFrames",
 
121
        sizeof (MetaFrames),
 
122
        sizeof (MetaFramesClass),
 
123
        (GtkClassInitFunc) meta_frames_class_init,
 
124
        (GtkObjectInitFunc) meta_frames_init,
 
125
        /* reserved_1 */ NULL,
 
126
        /* reserved_2 */ NULL,
 
127
        (GtkClassInitFunc) NULL,
 
128
      };
 
129
 
 
130
      frames_type = gtk_type_unique (GTK_TYPE_WINDOW, &frames_info);
 
131
    }
 
132
 
 
133
  return frames_type;
 
134
}
 
135
 
 
136
static void
 
137
meta_frames_class_init (MetaFramesClass *class)
 
138
{
 
139
  GObjectClass   *gobject_class;
 
140
  GtkObjectClass *object_class;
 
141
  GtkWidgetClass *widget_class;
 
142
 
 
143
  gobject_class = G_OBJECT_CLASS (class);
 
144
  object_class = (GtkObjectClass*) class;
 
145
  widget_class = (GtkWidgetClass*) class;
 
146
 
 
147
  parent_class = g_type_class_peek_parent (class);
 
148
 
 
149
  gobject_class->finalize = meta_frames_finalize;
 
150
  object_class->destroy = meta_frames_destroy;
 
151
 
 
152
  widget_class->style_set = meta_frames_style_set;
 
153
 
 
154
  widget_class->realize = meta_frames_realize;
 
155
  widget_class->unrealize = meta_frames_unrealize;
 
156
  
 
157
  widget_class->expose_event = meta_frames_expose_event;
 
158
  widget_class->destroy_event = meta_frames_destroy_event;  
 
159
  widget_class->button_press_event = meta_frames_button_press_event;
 
160
  widget_class->button_release_event = meta_frames_button_release_event;
 
161
  widget_class->motion_notify_event = meta_frames_motion_notify_event;
 
162
  widget_class->enter_notify_event = meta_frames_enter_notify_event;
 
163
  widget_class->leave_notify_event = meta_frames_leave_notify_event;
 
164
}
 
165
 
 
166
static gint
 
167
unsigned_long_equal (gconstpointer v1,
 
168
                     gconstpointer v2)
 
169
{
 
170
  return *((const gulong*) v1) == *((const gulong*) v2);
 
171
}
 
172
 
 
173
static guint
 
174
unsigned_long_hash (gconstpointer v)
 
175
{
 
176
  gulong val = * (const gulong *) v;
 
177
 
 
178
  /* I'm not sure this works so well. */
 
179
#if GLIB_SIZEOF_LONG > 4
 
180
  return (guint) (val ^ (val >> 32));
 
181
#else
 
182
  return val;
 
183
#endif
 
184
}
 
185
 
 
186
static void
 
187
prefs_changed_callback (MetaPreference pref,
 
188
                        void          *data)
 
189
{
 
190
  switch (pref)
 
191
    {
 
192
    case META_PREF_TITLEBAR_FONT:
 
193
      meta_frames_font_changed (META_FRAMES (data));
 
194
      break;
 
195
    case META_PREF_BUTTON_LAYOUT:
 
196
      meta_frames_button_layout_changed (META_FRAMES (data));
 
197
      break;
 
198
    default:
 
199
      break;
 
200
    }
 
201
}
 
202
 
 
203
static void
 
204
meta_frames_init (MetaFrames *frames)
 
205
{
 
206
  GTK_WINDOW (frames)->type = GTK_WINDOW_POPUP;
 
207
 
 
208
  frames->text_heights = g_hash_table_new (NULL, NULL);
 
209
  
 
210
  frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
 
211
 
 
212
  frames->tooltip_timeout = 0;
 
213
 
 
214
  frames->expose_delay_count = 0;
 
215
 
 
216
  frames->invalidate_cache_timeout_id = 0;
 
217
  frames->invalidate_frames = NULL;
 
218
  frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal);
 
219
 
 
220
  gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE);
 
221
 
 
222
  meta_prefs_add_listener (prefs_changed_callback, frames);
 
223
}
 
224
 
 
225
static void
 
226
listify_func (gpointer key, gpointer value, gpointer data)
 
227
{
 
228
  GSList **listp;
 
229
 
 
230
  listp = data;
 
231
  *listp = g_slist_prepend (*listp, value);
 
232
}
 
233
 
 
234
static void
 
235
meta_frames_destroy (GtkObject *object)
 
236
{
 
237
  GSList *winlist;
 
238
  GSList *tmp;
 
239
  MetaFrames *frames;
 
240
  
 
241
  frames = META_FRAMES (object);
 
242
 
 
243
  clear_tip (frames);
 
244
  
 
245
  winlist = NULL;
 
246
  g_hash_table_foreach (frames->frames, listify_func, &winlist);
 
247
 
 
248
  /* Unmanage all frames */
 
249
  for (tmp = winlist; tmp != NULL; tmp = tmp->next)
 
250
    {
 
251
      MetaUIFrame *frame;
 
252
 
 
253
      frame = tmp->data;
 
254
 
 
255
      meta_frames_unmanage_window (frames, frame->xwindow);
 
256
    }
 
257
  g_slist_free (winlist);
 
258
 
 
259
  GTK_OBJECT_CLASS (parent_class)->destroy (object);
 
260
}
 
261
 
 
262
static void
 
263
meta_frames_finalize (GObject *object)
 
264
{
 
265
  MetaFrames *frames;
 
266
  
 
267
  frames = META_FRAMES (object);
 
268
 
 
269
  meta_prefs_remove_listener (prefs_changed_callback, frames);
 
270
  
 
271
  g_hash_table_destroy (frames->text_heights);
 
272
 
 
273
  invalidate_all_caches (frames);
 
274
  if (frames->invalidate_cache_timeout_id)
 
275
    g_source_remove (frames->invalidate_cache_timeout_id);
 
276
  
 
277
  g_assert (g_hash_table_size (frames->frames) == 0);
 
278
  g_hash_table_destroy (frames->frames);
 
279
  g_hash_table_destroy (frames->cache);
 
280
 
 
281
  G_OBJECT_CLASS (parent_class)->finalize (object);
 
282
}
 
283
 
 
284
typedef struct
 
285
{
 
286
  MetaRectangle rect;
 
287
  GdkPixmap *pixmap;
 
288
} CachedFramePiece;
 
289
 
 
290
typedef struct
 
291
{
 
292
  /* Caches of the four rendered sides in a MetaFrame.
 
293
   * Order: top (titlebar), left, right, bottom.
 
294
   */
 
295
  CachedFramePiece piece[4];
 
296
} CachedPixels;
 
297
 
 
298
static CachedPixels *
 
299
get_cache (MetaFrames *frames,
 
300
           MetaUIFrame *frame)
 
301
{
 
302
  CachedPixels *pixels;
 
303
  
 
304
  pixels = g_hash_table_lookup (frames->cache, frame);
 
305
 
 
306
  if (!pixels)
 
307
    {
 
308
      pixels = g_new0 (CachedPixels, 1);
 
309
      g_hash_table_insert (frames->cache, frame, pixels);
 
310
    }
 
311
 
 
312
  return pixels;
 
313
}
 
314
 
 
315
static void
 
316
invalidate_cache (MetaFrames *frames,
 
317
                  MetaUIFrame *frame)
 
318
{
 
319
  CachedPixels *pixels = get_cache (frames, frame);
 
320
  int i;
 
321
  
 
322
  for (i = 0; i < 4; i++)
 
323
    if (pixels->piece[i].pixmap)
 
324
      g_object_unref (pixels->piece[i].pixmap);
 
325
  
 
326
  g_free (pixels);
 
327
  g_hash_table_remove (frames->cache, frame);
 
328
}
 
329
 
 
330
static void
 
331
invalidate_all_caches (MetaFrames *frames)
 
332
{
 
333
  GList *l;
 
334
 
 
335
  for (l = frames->invalidate_frames; l; l = l->next)
 
336
    {
 
337
      MetaUIFrame *frame = l->data;
 
338
 
 
339
      invalidate_cache (frames, frame);
 
340
    }
 
341
  
 
342
  g_list_free (frames->invalidate_frames);
 
343
  frames->invalidate_frames = NULL;
 
344
}
 
345
 
 
346
static gboolean
 
347
invalidate_cache_timeout (gpointer data)
 
348
{
 
349
  MetaFrames *frames = data;
 
350
  
 
351
  invalidate_all_caches (frames);
 
352
  frames->invalidate_cache_timeout_id = 0;
 
353
  return FALSE;
 
354
}
 
355
 
 
356
static void
 
357
queue_recalc_func (gpointer key, gpointer value, gpointer data)
 
358
{
 
359
  MetaUIFrame *frame;
 
360
  MetaFrames *frames;
 
361
 
 
362
  frames = META_FRAMES (data);
 
363
  frame = value;
 
364
 
 
365
  /* If a resize occurs it will cause a redraw, but the
 
366
   * resize may not actually be needed so we always redraw
 
367
   * in case of color change.
 
368
   */
 
369
  meta_frames_set_window_background (frames, frame);
 
370
  
 
371
  invalidate_whole_window (frames, frame);
 
372
  meta_core_queue_frame_resize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
373
                                frame->xwindow);
 
374
  if (frame->layout)
 
375
    {
 
376
      /* save title to recreate layout */
 
377
      g_free (frame->title);
 
378
      
 
379
      frame->title = g_strdup (pango_layout_get_text (frame->layout));
 
380
 
 
381
      g_object_unref (G_OBJECT (frame->layout));
 
382
      frame->layout = NULL;
 
383
    }
 
384
}
 
385
 
 
386
static void
 
387
meta_frames_font_changed (MetaFrames *frames)
 
388
{
 
389
  if (g_hash_table_size (frames->text_heights) > 0)
 
390
    {
 
391
      g_hash_table_destroy (frames->text_heights);
 
392
      frames->text_heights = g_hash_table_new (NULL, NULL);
 
393
    }
 
394
  
 
395
  /* Queue a draw/resize on all frames */
 
396
  g_hash_table_foreach (frames->frames,
 
397
                        queue_recalc_func, frames);
 
398
 
 
399
}
 
400
 
 
401
static void
 
402
queue_draw_func (gpointer key, gpointer value, gpointer data)
 
403
{
 
404
  MetaUIFrame *frame;
 
405
  MetaFrames *frames;
 
406
 
 
407
  frames = META_FRAMES (data);
 
408
  frame = value;
 
409
 
 
410
  /* If a resize occurs it will cause a redraw, but the
 
411
   * resize may not actually be needed so we always redraw
 
412
   * in case of color change.
 
413
   */
 
414
  meta_frames_set_window_background (frames, frame);
 
415
 
 
416
  invalidate_whole_window (frames, frame);
 
417
}
 
418
 
 
419
static void
 
420
meta_frames_button_layout_changed (MetaFrames *frames)
 
421
{
 
422
  g_hash_table_foreach (frames->frames,
 
423
                        queue_draw_func, frames);
 
424
}
 
425
 
 
426
static void
 
427
reattach_style_func (gpointer key, gpointer value, gpointer data)
 
428
{
 
429
  MetaUIFrame *frame;
 
430
  MetaFrames *frames;
 
431
 
 
432
  frames = META_FRAMES (data);
 
433
  frame = value;
 
434
 
 
435
  meta_frames_attach_style (frames, frame);
 
436
}
 
437
 
 
438
static void
 
439
meta_frames_style_set  (GtkWidget *widget,
 
440
                        GtkStyle  *prev_style)
 
441
{
 
442
  MetaFrames *frames;
 
443
 
 
444
  frames = META_FRAMES (widget);
 
445
 
 
446
  meta_frames_font_changed (frames);
 
447
 
 
448
  g_hash_table_foreach (frames->frames,
 
449
                        reattach_style_func, frames);
 
450
 
 
451
  GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
 
452
}
 
453
 
 
454
static void
 
455
meta_frames_ensure_layout (MetaFrames  *frames,
 
456
                           MetaUIFrame *frame)
 
457
{
 
458
  GtkWidget *widget;
 
459
  MetaFrameFlags flags;
 
460
  MetaFrameType type;
 
461
  MetaFrameStyle *style;
 
462
  
 
463
  g_return_if_fail (GTK_WIDGET_REALIZED (frames));
 
464
 
 
465
  widget = GTK_WIDGET (frames);
 
466
      
 
467
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
468
                 META_CORE_GET_FRAME_FLAGS, &flags,
 
469
                 META_CORE_GET_FRAME_TYPE, &type,
 
470
                 META_CORE_GET_END);
 
471
 
 
472
  style = meta_theme_get_frame_style (meta_theme_get_current (),
 
473
                                      type, flags);
 
474
 
 
475
  if (style != frame->cache_style)
 
476
    {
 
477
      if (frame->layout)
 
478
        {
 
479
          /* save title to recreate layout */
 
480
          g_free (frame->title);
 
481
          
 
482
          frame->title = g_strdup (pango_layout_get_text (frame->layout));
 
483
 
 
484
          g_object_unref (G_OBJECT (frame->layout));
 
485
          frame->layout = NULL;
 
486
        }
 
487
    }
 
488
 
 
489
  frame->cache_style = style;
 
490
  
 
491
  if (frame->layout == NULL)
 
492
    {
 
493
      gpointer key, value;
 
494
      PangoFontDescription *font_desc;
 
495
      double scale;
 
496
      int size;
 
497
      
 
498
      scale = meta_theme_get_title_scale (meta_theme_get_current (),
 
499
                                          type,
 
500
                                          flags);
 
501
      
 
502
      frame->layout = gtk_widget_create_pango_layout (widget, frame->title);
 
503
 
 
504
      pango_layout_set_auto_dir (frame->layout, FALSE);
 
505
      
 
506
      font_desc = meta_gtk_widget_get_font_desc (widget, scale,
 
507
                                                 meta_prefs_get_titlebar_font ());
 
508
 
 
509
      size = pango_font_description_get_size (font_desc);
 
510
 
 
511
      if (g_hash_table_lookup_extended (frames->text_heights,
 
512
                                        GINT_TO_POINTER (size),
 
513
                                        &key, &value))
 
514
        {
 
515
          frame->text_height = GPOINTER_TO_INT (value);
 
516
        }
 
517
      else
 
518
        {
 
519
          frame->text_height =
 
520
            meta_pango_font_desc_get_text_height (font_desc,
 
521
                                                  gtk_widget_get_pango_context (widget));
 
522
 
 
523
          g_hash_table_replace (frames->text_heights,
 
524
                                GINT_TO_POINTER (size),
 
525
                                GINT_TO_POINTER (frame->text_height));
 
526
        }
 
527
      
 
528
      pango_layout_set_font_description (frame->layout, 
 
529
                                         font_desc);
 
530
      
 
531
      pango_font_description_free (font_desc);
 
532
 
 
533
      /* Save some RAM */
 
534
      g_free (frame->title);
 
535
      frame->title = NULL;
 
536
    }
 
537
}
 
538
 
 
539
static void
 
540
meta_frames_calc_geometry (MetaFrames        *frames,
 
541
                           MetaUIFrame       *frame,
 
542
                           MetaFrameGeometry *fgeom)
 
543
{
 
544
  int width, height;
 
545
  MetaFrameFlags flags;
 
546
  MetaFrameType type;
 
547
  MetaButtonLayout button_layout;
 
548
  
 
549
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
550
                 META_CORE_GET_CLIENT_WIDTH, &width,
 
551
                 META_CORE_GET_CLIENT_HEIGHT, &height,
 
552
                 META_CORE_GET_FRAME_FLAGS, &flags,
 
553
                 META_CORE_GET_FRAME_TYPE, &type,
 
554
                 META_CORE_GET_END);
 
555
 
 
556
  meta_frames_ensure_layout (frames, frame);
 
557
 
 
558
  meta_prefs_get_button_layout (&button_layout);
 
559
  
 
560
  meta_theme_calc_geometry (meta_theme_get_current (),
 
561
                            type,
 
562
                            frame->text_height,
 
563
                            flags,
 
564
                            width, height,
 
565
                            &button_layout,
 
566
                            fgeom);
 
567
}
 
568
 
 
569
MetaFrames*
 
570
meta_frames_new (int screen_number)
 
571
{
 
572
  GdkScreen *screen;
 
573
 
 
574
  screen = gdk_display_get_screen (gdk_display_get_default (),
 
575
                                   screen_number);
 
576
 
 
577
  return g_object_new (META_TYPE_FRAMES,
 
578
                       "screen", screen,
 
579
                       NULL);  
 
580
}
 
581
 
 
582
/* In order to use a style with a window it has to be attached to that
 
583
 * window. Actually, the colormaps just have to match, but since GTK+
 
584
 * already takes care of making sure that its cheap to attach a style
 
585
 * to multiple windows with the same colormap, we can just go ahead
 
586
 * and attach separately for each window.
 
587
 */
 
588
static void
 
589
meta_frames_attach_style (MetaFrames  *frames,
 
590
                          MetaUIFrame *frame)
 
591
{
 
592
  if (frame->style != NULL)
 
593
    gtk_style_detach (frame->style);
 
594
 
 
595
  /* Weirdly, gtk_style_attach() steals a reference count from the style passed in */
 
596
  g_object_ref (GTK_WIDGET (frames)->style);
 
597
  frame->style = gtk_style_attach (GTK_WIDGET (frames)->style, frame->window);
 
598
}
 
599
 
 
600
void
 
601
meta_frames_manage_window (MetaFrames *frames,
 
602
                           Window      xwindow,
 
603
                           GdkWindow  *window)
 
604
{
 
605
  MetaUIFrame *frame;
 
606
 
 
607
  g_assert (window);
 
608
 
 
609
  frame = g_new (MetaUIFrame, 1);
 
610
  
 
611
  frame->window = window;
 
612
 
 
613
  gdk_window_set_user_data (frame->window, frames);
 
614
 
 
615
  frame->style = NULL;
 
616
  meta_frames_attach_style (frames, frame);
 
617
 
 
618
  /* Don't set event mask here, it's in frame.c */
 
619
  
 
620
  frame->xwindow = xwindow;
 
621
  frame->cache_style = NULL;
 
622
  frame->layout = NULL;
 
623
  frame->text_height = -1;
 
624
  frame->title = NULL;
 
625
  frame->expose_delayed = FALSE;
 
626
  frame->shape_applied = FALSE;
 
627
  frame->prelit_control = META_FRAME_CONTROL_NONE;
 
628
 
 
629
  /* Don't set the window background yet; we need frame->xwindow to be
 
630
   * registered with its MetaWindow, which happens after this function
 
631
   * and meta_ui_create_frame_window() return to meta_window_ensure_frame().
 
632
   */
 
633
  
 
634
  meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
635
  
 
636
  g_hash_table_replace (frames->frames, &frame->xwindow, frame);
 
637
}
 
638
 
 
639
void
 
640
meta_frames_unmanage_window (MetaFrames *frames,
 
641
                             Window      xwindow)
 
642
{
 
643
  MetaUIFrame *frame;
 
644
 
 
645
  clear_tip (frames);
 
646
  
 
647
  frame = g_hash_table_lookup (frames->frames, &xwindow);
 
648
 
 
649
  if (frame)
 
650
    {
 
651
      /* invalidating all caches ensures the frame
 
652
       * is not actually referenced anymore
 
653
       */
 
654
      invalidate_all_caches (frames);
 
655
      
 
656
      /* restore the cursor */
 
657
      meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
658
                                   frame->xwindow,
 
659
                                   META_CURSOR_DEFAULT);
 
660
 
 
661
      gdk_window_set_user_data (frame->window, NULL);
 
662
 
 
663
      if (frames->last_motion_frame == frame)
 
664
        frames->last_motion_frame = NULL;
 
665
      
 
666
      g_hash_table_remove (frames->frames, &frame->xwindow);
 
667
 
 
668
      gtk_style_detach (frame->style);
 
669
 
 
670
      gdk_window_destroy (frame->window);
 
671
 
 
672
      if (frame->layout)
 
673
        g_object_unref (G_OBJECT (frame->layout));
 
674
 
 
675
      if (frame->title)
 
676
        g_free (frame->title);
 
677
      
 
678
      g_free (frame);
 
679
    }
 
680
  else
 
681
    meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
 
682
}
 
683
 
 
684
static void
 
685
meta_frames_realize (GtkWidget *widget)
 
686
{
 
687
  if (GTK_WIDGET_CLASS (parent_class)->realize)
 
688
    GTK_WIDGET_CLASS (parent_class)->realize (widget);
 
689
}
 
690
 
 
691
static void
 
692
meta_frames_unrealize (GtkWidget *widget)
 
693
{
 
694
  if (GTK_WIDGET_CLASS (parent_class)->unrealize)
 
695
    GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
 
696
}
 
697
 
 
698
static MetaUIFrame*
 
699
meta_frames_lookup_window (MetaFrames *frames,
 
700
                           Window      xwindow)
 
701
{
 
702
  MetaUIFrame *frame;
 
703
 
 
704
  frame = g_hash_table_lookup (frames->frames, &xwindow);
 
705
 
 
706
  return frame;
 
707
}
 
708
 
 
709
void
 
710
meta_frames_get_geometry (MetaFrames *frames,
 
711
                          Window xwindow,
 
712
                          int *top_height, int *bottom_height,
 
713
                          int *left_width, int *right_width)
 
714
{
 
715
  MetaFrameFlags flags;
 
716
  MetaUIFrame *frame;
 
717
  MetaFrameType type;
 
718
  
 
719
  frame = meta_frames_lookup_window (frames, xwindow);
 
720
 
 
721
  if (frame == NULL)
 
722
    meta_bug ("No such frame 0x%lx\n", xwindow);
 
723
  
 
724
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
725
                 META_CORE_GET_FRAME_FLAGS, &flags,
 
726
                 META_CORE_GET_FRAME_TYPE, &type,
 
727
                 META_CORE_GET_END);
 
728
 
 
729
  g_return_if_fail (type < META_FRAME_TYPE_LAST);
 
730
 
 
731
  meta_frames_ensure_layout (frames, frame);
 
732
  
 
733
  /* We can't get the full geometry, because that depends on
 
734
   * the client window size and probably we're being called
 
735
   * by the core move/resize code to decide on the client
 
736
   * window size
 
737
   */
 
738
  meta_theme_get_frame_borders (meta_theme_get_current (),
 
739
                                type,
 
740
                                frame->text_height,
 
741
                                flags,
 
742
                                top_height, bottom_height,
 
743
                                left_width, right_width);
 
744
}
 
745
 
 
746
void
 
747
meta_frames_reset_bg (MetaFrames *frames,
 
748
                      Window  xwindow)
 
749
{
 
750
  MetaUIFrame *frame;
 
751
  
 
752
  frame = meta_frames_lookup_window (frames, xwindow);
 
753
 
 
754
  meta_frames_set_window_background (frames, frame);
 
755
}
 
756
 
 
757
static void
 
758
set_background_none (Display *xdisplay,
 
759
                     Window   xwindow)
 
760
{
 
761
  XSetWindowAttributes attrs;
 
762
 
 
763
  attrs.background_pixmap = None;
 
764
  XChangeWindowAttributes (xdisplay, xwindow,
 
765
                           CWBackPixmap, &attrs);
 
766
}
 
767
 
 
768
void
 
769
meta_frames_unflicker_bg (MetaFrames *frames,
 
770
                          Window      xwindow,
 
771
                          int         target_width,
 
772
                          int         target_height)
 
773
{
 
774
  MetaUIFrame *frame;
 
775
  
 
776
  frame = meta_frames_lookup_window (frames, xwindow);
 
777
  g_return_if_fail (frame != NULL);
 
778
 
 
779
#if 0
 
780
  pixmap = gdk_pixmap_new (frame->window,
 
781
                           width, height,
 
782
                           -1);
 
783
 
 
784
  /* Oops, no way to get the background here */
 
785
  
 
786
  meta_frames_paint_to_drawable (frames, frame, pixmap);
 
787
#endif
 
788
 
 
789
  set_background_none (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
790
}
 
791
 
 
792
void
 
793
meta_frames_apply_shapes (MetaFrames *frames,
 
794
                          Window      xwindow,
 
795
                          int         new_window_width,
 
796
                          int         new_window_height,
 
797
                          gboolean    window_has_shape)
 
798
{
 
799
#ifdef HAVE_SHAPE
 
800
  /* Apply shapes as if window had new_window_width, new_window_height */
 
801
  MetaUIFrame *frame;
 
802
  MetaFrameGeometry fgeom;
 
803
  XRectangle xrect;
 
804
  Region corners_xregion;
 
805
  Region window_xregion;
 
806
  
 
807
  frame = meta_frames_lookup_window (frames, xwindow);
 
808
  g_return_if_fail (frame != NULL);
 
809
 
 
810
  meta_frames_calc_geometry (frames, frame, &fgeom);
 
811
 
 
812
  if (!(fgeom.top_left_corner_rounded_radius != 0 ||
 
813
        fgeom.top_right_corner_rounded_radius != 0 ||
 
814
        fgeom.bottom_left_corner_rounded_radius != 0 ||
 
815
        fgeom.bottom_right_corner_rounded_radius != 0 ||
 
816
        window_has_shape))
 
817
    {
 
818
      if (frame->shape_applied)
 
819
        {
 
820
          meta_topic (META_DEBUG_SHAPES,
 
821
                      "Unsetting shape mask on frame 0x%lx\n",
 
822
                      frame->xwindow);
 
823
          
 
824
          XShapeCombineMask (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
825
                             ShapeBounding, 0, 0, None, ShapeSet);
 
826
          frame->shape_applied = FALSE;
 
827
        }
 
828
      else
 
829
        {
 
830
          meta_topic (META_DEBUG_SHAPES,
 
831
                      "Frame 0x%lx still doesn't need a shape mask\n",
 
832
                      frame->xwindow);
 
833
        }
 
834
      
 
835
      return; /* nothing to do */
 
836
    }
 
837
  
 
838
  corners_xregion = XCreateRegion ();
 
839
  
 
840
  if (fgeom.top_left_corner_rounded_radius != 0)
 
841
    {
 
842
      const int corner = fgeom.top_left_corner_rounded_radius;
 
843
      const float radius = sqrt(corner) + corner;
 
844
      int i;
 
845
 
 
846
      for (i=0; i<corner; i++)
 
847
        {
 
848
          const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
 
849
          xrect.x = 0;
 
850
          xrect.y = i;
 
851
          xrect.width = width;
 
852
          xrect.height = 1;
 
853
          
 
854
          XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
855
        }
 
856
    }
 
857
 
 
858
  if (fgeom.top_right_corner_rounded_radius != 0)
 
859
    {
 
860
      const int corner = fgeom.top_right_corner_rounded_radius;
 
861
      const float radius = sqrt(corner) + corner;
 
862
      int i;
 
863
 
 
864
      for (i=0; i<corner; i++)
 
865
        {
 
866
          const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
 
867
          xrect.x = new_window_width - width;
 
868
          xrect.y = i;
 
869
          xrect.width = width;
 
870
          xrect.height = 1;
 
871
          
 
872
          XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
873
        }
 
874
    }
 
875
 
 
876
  if (fgeom.bottom_left_corner_rounded_radius != 0)
 
877
    {
 
878
      const int corner = fgeom.bottom_left_corner_rounded_radius;
 
879
      const float radius = sqrt(corner) + corner;
 
880
      int i;
 
881
 
 
882
      for (i=0; i<corner; i++)
 
883
        {
 
884
          const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
 
885
          xrect.x = 0;
 
886
          xrect.y = new_window_height - i - 1;
 
887
          xrect.width = width;
 
888
          xrect.height = 1;
 
889
          
 
890
          XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
891
        }
 
892
    }
 
893
 
 
894
  if (fgeom.bottom_right_corner_rounded_radius != 0)
 
895
    {
 
896
      const int corner = fgeom.bottom_right_corner_rounded_radius;
 
897
      const float radius = sqrt(corner) + corner;
 
898
      int i;
 
899
 
 
900
      for (i=0; i<corner; i++)
 
901
        {
 
902
          const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
 
903
          xrect.x = new_window_width - width;
 
904
          xrect.y = new_window_height - i - 1;
 
905
          xrect.width = width;
 
906
          xrect.height = 1;
 
907
          
 
908
          XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
909
        }
 
910
    }
 
911
  
 
912
  window_xregion = XCreateRegion ();
 
913
  
 
914
  xrect.x = 0;
 
915
  xrect.y = 0;
 
916
  xrect.width = new_window_width;
 
917
  xrect.height = new_window_height;
 
918
 
 
919
  XUnionRectWithRegion (&xrect, window_xregion, window_xregion);
 
920
 
 
921
  XSubtractRegion (window_xregion, corners_xregion, window_xregion);
 
922
 
 
923
  XDestroyRegion (corners_xregion);
 
924
  
 
925
  if (window_has_shape)
 
926
    {
 
927
      /* The client window is oclock or something and has a shape
 
928
       * mask. To avoid a round trip to get its shape region, we
 
929
       * create a fake window that's never mapped, build up our shape
 
930
       * on that, then combine. Wasting the window is assumed cheaper
 
931
       * than a round trip, but who really knows for sure.
 
932
       */
 
933
      XSetWindowAttributes attrs;      
 
934
      Window shape_window;
 
935
      Window client_window;
 
936
      Region client_xregion;
 
937
      GdkScreen *screen;
 
938
      int screen_number;
 
939
      
 
940
      meta_topic (META_DEBUG_SHAPES,
 
941
                  "Frame 0x%lx needs to incorporate client shape\n",
 
942
                  frame->xwindow);
 
943
 
 
944
      screen = gtk_widget_get_screen (GTK_WIDGET (frames));
 
945
      screen_number = gdk_x11_screen_get_screen_number (screen);
 
946
      
 
947
      attrs.override_redirect = True;
 
948
      
 
949
      shape_window = XCreateWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
950
                                    RootWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), screen_number),
 
951
                                    -5000, -5000,
 
952
                                    new_window_width,
 
953
                                    new_window_height,
 
954
                                    0,
 
955
                                    CopyFromParent,
 
956
                                    CopyFromParent,
 
957
                                    (Visual *)CopyFromParent,
 
958
                                    CWOverrideRedirect,
 
959
                                    &attrs);
 
960
 
 
961
      /* Copy the client's shape to the temporary shape_window */
 
962
      meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
963
                     META_CORE_GET_CLIENT_XWINDOW, &client_window,
 
964
                     META_CORE_GET_END);
 
965
 
 
966
      XShapeCombineShape (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), shape_window, ShapeBounding,
 
967
                          fgeom.left_width,
 
968
                          fgeom.top_height,
 
969
                          client_window,
 
970
                          ShapeBounding,
 
971
                          ShapeSet);
 
972
 
 
973
      /* Punch the client area out of the normal frame shape,
 
974
       * then union it with the shape_window's existing shape
 
975
       */
 
976
      client_xregion = XCreateRegion ();
 
977
  
 
978
      xrect.x = fgeom.left_width;
 
979
      xrect.y = fgeom.top_height;
 
980
      xrect.width = new_window_width - fgeom.right_width - xrect.x;
 
981
      xrect.height = new_window_height - fgeom.bottom_height - xrect.y;
 
982
 
 
983
      XUnionRectWithRegion (&xrect, client_xregion, client_xregion);
 
984
      
 
985
      XSubtractRegion (window_xregion, client_xregion, window_xregion);
 
986
 
 
987
      XDestroyRegion (client_xregion);
 
988
      
 
989
      XShapeCombineRegion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), shape_window,
 
990
                           ShapeBounding, 0, 0, window_xregion, ShapeUnion);
 
991
      
 
992
      /* Now copy shape_window shape to the real frame */
 
993
      XShapeCombineShape (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, ShapeBounding,
 
994
                          0, 0,
 
995
                          shape_window,
 
996
                          ShapeBounding,
 
997
                          ShapeSet);
 
998
 
 
999
      XDestroyWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), shape_window);
 
1000
    }
 
1001
  else
 
1002
    {
 
1003
      /* No shape on the client, so just do simple stuff */
 
1004
 
 
1005
      meta_topic (META_DEBUG_SHAPES,
 
1006
                  "Frame 0x%lx has shaped corners\n",
 
1007
                  frame->xwindow);
 
1008
      
 
1009
      XShapeCombineRegion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1010
                           ShapeBounding, 0, 0, window_xregion, ShapeSet);
 
1011
    }
 
1012
  
 
1013
  frame->shape_applied = TRUE;
 
1014
  
 
1015
  XDestroyRegion (window_xregion);
 
1016
#endif /* HAVE_SHAPE */
 
1017
}
 
1018
 
 
1019
void
 
1020
meta_frames_move_resize_frame (MetaFrames *frames,
 
1021
                               Window      xwindow,
 
1022
                               int         x,
 
1023
                               int         y,
 
1024
                               int         width,
 
1025
                               int         height)
 
1026
{
 
1027
  MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow);
 
1028
  int old_x, old_y, old_width, old_height;
 
1029
  
 
1030
  gdk_drawable_get_size (frame->window, &old_width, &old_height);
 
1031
  gdk_window_get_position (frame->window, &old_x, &old_y);
 
1032
 
 
1033
  gdk_window_move_resize (frame->window, x, y, width, height);
 
1034
 
 
1035
  if (old_width != width || old_height != height)
 
1036
    invalidate_whole_window (frames, frame);
 
1037
}
 
1038
 
 
1039
void
 
1040
meta_frames_queue_draw (MetaFrames *frames,
 
1041
                        Window      xwindow)
 
1042
{
 
1043
  MetaUIFrame *frame;
 
1044
  
 
1045
  frame = meta_frames_lookup_window (frames, xwindow);
 
1046
 
 
1047
  invalidate_whole_window (frames, frame);
 
1048
}
 
1049
 
 
1050
void
 
1051
meta_frames_set_title (MetaFrames *frames,
 
1052
                       Window      xwindow,
 
1053
                       const char *title)
 
1054
{
 
1055
  MetaUIFrame *frame;
 
1056
  
 
1057
  frame = meta_frames_lookup_window (frames, xwindow);
 
1058
 
 
1059
  g_assert (frame);
 
1060
  
 
1061
  g_free (frame->title);
 
1062
  frame->title = g_strdup (title);
 
1063
  
 
1064
  if (frame->layout)
 
1065
    {
 
1066
      g_object_unref (frame->layout);
 
1067
      frame->layout = NULL;
 
1068
    }
 
1069
 
 
1070
  invalidate_whole_window (frames, frame);
 
1071
}
 
1072
 
 
1073
void
 
1074
meta_frames_repaint_frame (MetaFrames *frames,
 
1075
                           Window      xwindow)
 
1076
{
 
1077
  MetaUIFrame *frame;
 
1078
  
 
1079
  frame = meta_frames_lookup_window (frames, xwindow);
 
1080
 
 
1081
  g_assert (frame);
 
1082
 
 
1083
  /* repaint everything, so the other frame don't
 
1084
   * lag behind if they are exposed
 
1085
   */
 
1086
  gdk_window_process_all_updates ();
 
1087
}
 
1088
 
 
1089
static void
 
1090
show_tip_now (MetaFrames *frames)
 
1091
{
 
1092
  const char *tiptext;
 
1093
  MetaUIFrame *frame;
 
1094
  int x, y, root_x, root_y;
 
1095
  Window root, child;
 
1096
  guint mask;
 
1097
  MetaFrameControl control;
 
1098
  
 
1099
  frame = frames->last_motion_frame;
 
1100
  if (frame == NULL)
 
1101
    return;
 
1102
 
 
1103
  if (meta_prefs_get_hide_decorator_tooltip ())
 
1104
    return;
 
1105
 
 
1106
  XQueryPointer (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1107
                 frame->xwindow,
 
1108
                 &root, &child,
 
1109
                 &root_x, &root_y,
 
1110
                 &x, &y,
 
1111
                 &mask);
 
1112
  
 
1113
  control = get_control (frames, frame, x, y);
 
1114
  
 
1115
  tiptext = NULL;
 
1116
  switch (control)
 
1117
    {
 
1118
    case META_FRAME_CONTROL_TITLE:
 
1119
      break;
 
1120
    case META_FRAME_CONTROL_DELETE:
 
1121
      tiptext = _("Close Window");
 
1122
      break;
 
1123
    case META_FRAME_CONTROL_MENU:
 
1124
      tiptext = _("Window Menu");
 
1125
      break;
 
1126
    case META_FRAME_CONTROL_MINIMIZE:
 
1127
      tiptext = _("Minimize Window");
 
1128
      break;
 
1129
    case META_FRAME_CONTROL_MAXIMIZE:
 
1130
      tiptext = _("Maximize Window");
 
1131
      break;
 
1132
    case META_FRAME_CONTROL_UNMAXIMIZE:
 
1133
      tiptext = _("Restore Window");
 
1134
      break;
 
1135
    case META_FRAME_CONTROL_SHADE:
 
1136
      tiptext = _("Roll Up Window");
 
1137
      break;
 
1138
    case META_FRAME_CONTROL_UNSHADE:
 
1139
      tiptext = _("Unroll Window");
 
1140
      break;
 
1141
    case META_FRAME_CONTROL_ABOVE:
 
1142
      tiptext = _("Keep Window On Top");
 
1143
      break;
 
1144
    case META_FRAME_CONTROL_UNABOVE:
 
1145
      tiptext = _("Remove Window From Top");
 
1146
      break;
 
1147
    case META_FRAME_CONTROL_STICK:
 
1148
      tiptext = _("Always On Visible Workspace");
 
1149
      break;
 
1150
    case META_FRAME_CONTROL_UNSTICK:
 
1151
      tiptext = _("Put Window On Only One Workspace");
 
1152
      break;
 
1153
    case META_FRAME_CONTROL_RESIZE_SE:
 
1154
      break;
 
1155
    case META_FRAME_CONTROL_RESIZE_S:
 
1156
      break;
 
1157
    case META_FRAME_CONTROL_RESIZE_SW:
 
1158
      break;
 
1159
    case META_FRAME_CONTROL_RESIZE_N:
 
1160
      break;
 
1161
    case META_FRAME_CONTROL_RESIZE_NE:
 
1162
      break;
 
1163
    case META_FRAME_CONTROL_RESIZE_NW:
 
1164
      break;
 
1165
    case META_FRAME_CONTROL_RESIZE_W:
 
1166
      break;
 
1167
    case META_FRAME_CONTROL_RESIZE_E:
 
1168
      break;
 
1169
    case META_FRAME_CONTROL_NONE:      
 
1170
      break;
 
1171
    case META_FRAME_CONTROL_CLIENT_AREA:
 
1172
      break;
 
1173
    }
 
1174
 
 
1175
  if (tiptext)
 
1176
    {
 
1177
      MetaFrameGeometry fgeom;
 
1178
      GdkRectangle *rect;
 
1179
      int dx, dy;
 
1180
      int screen_number;
 
1181
      
 
1182
      meta_frames_calc_geometry (frames, frame, &fgeom);
 
1183
      
 
1184
      rect = control_rect (control, &fgeom);
 
1185
 
 
1186
      /* get conversion delta for root-to-frame coords */
 
1187
      dx = root_x - x;
 
1188
      dy = root_y - y;
 
1189
 
 
1190
      /* Align the tooltip to the button right end if RTL */
 
1191
      if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
 
1192
        dx += rect->width;
 
1193
 
 
1194
      screen_number = gdk_screen_get_number (gtk_widget_get_screen (GTK_WIDGET (frames)));
 
1195
      
 
1196
      meta_fixed_tip_show (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1197
                           screen_number,
 
1198
                           rect->x + dx,
 
1199
                           rect->y + rect->height + 2 + dy,
 
1200
                           tiptext);
 
1201
    }
 
1202
}
 
1203
 
 
1204
static gboolean
 
1205
tip_timeout_func (gpointer data)
 
1206
{
 
1207
  MetaFrames *frames;
 
1208
 
 
1209
  frames = data;
 
1210
 
 
1211
  show_tip_now (frames);
 
1212
 
 
1213
  return FALSE;
 
1214
}
 
1215
 
 
1216
#define TIP_DELAY 450
 
1217
static void
 
1218
queue_tip (MetaFrames *frames)
 
1219
{
 
1220
  clear_tip (frames);
 
1221
  
 
1222
  frames->tooltip_timeout = g_timeout_add (TIP_DELAY,
 
1223
                                           tip_timeout_func,
 
1224
                                           frames);  
 
1225
}
 
1226
 
 
1227
static void
 
1228
clear_tip (MetaFrames *frames)
 
1229
{
 
1230
  if (frames->tooltip_timeout)
 
1231
    {
 
1232
      g_source_remove (frames->tooltip_timeout);
 
1233
      frames->tooltip_timeout = 0;
 
1234
    }
 
1235
  meta_fixed_tip_hide ();
 
1236
}
 
1237
 
 
1238
static void
 
1239
redraw_control (MetaFrames *frames,
 
1240
                MetaUIFrame *frame,
 
1241
                MetaFrameControl control)
 
1242
{
 
1243
  MetaFrameGeometry fgeom;
 
1244
  GdkRectangle *rect;
 
1245
  
 
1246
  meta_frames_calc_geometry (frames, frame, &fgeom);
 
1247
 
 
1248
  rect = control_rect (control, &fgeom);
 
1249
 
 
1250
  gdk_window_invalidate_rect (frame->window, rect, FALSE);
 
1251
  invalidate_cache (frames, frame);
 
1252
}
 
1253
 
 
1254
static gboolean
 
1255
meta_frame_titlebar_event (MetaUIFrame    *frame,
 
1256
                           GdkEventButton *event,
 
1257
                           int            action)
 
1258
{
 
1259
  MetaFrameFlags flags;
 
1260
  
 
1261
  switch (action)
 
1262
    {
 
1263
    case META_ACTION_TITLEBAR_TOGGLE_SHADE:
 
1264
      {
 
1265
        meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1266
                       META_CORE_GET_FRAME_FLAGS, &flags,
 
1267
                       META_CORE_GET_END);
 
1268
        
 
1269
        if (flags & META_FRAME_ALLOWS_SHADE)
 
1270
          {
 
1271
            if (flags & META_FRAME_SHADED)
 
1272
              meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1273
                                 frame->xwindow,
 
1274
                                 event->time);
 
1275
            else
 
1276
              meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1277
                               frame->xwindow,
 
1278
                               event->time);
 
1279
          }
 
1280
      }
 
1281
      break;          
 
1282
      
 
1283
    case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE:
 
1284
      {
 
1285
        meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1286
                       META_CORE_GET_FRAME_FLAGS, &flags,
 
1287
                       META_CORE_GET_END);
 
1288
        
 
1289
        if (flags & META_FRAME_ALLOWS_MAXIMIZE)
 
1290
          {
 
1291
            meta_core_toggle_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1292
          }
 
1293
      }
 
1294
      break;
 
1295
 
 
1296
    case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY:
 
1297
      {
 
1298
        meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1299
                       META_CORE_GET_FRAME_FLAGS, &flags,
 
1300
                       META_CORE_GET_END);
 
1301
        
 
1302
        if (flags & META_FRAME_ALLOWS_MAXIMIZE)
 
1303
          {
 
1304
            meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1305
          }
 
1306
      }
 
1307
      break;
 
1308
 
 
1309
    case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY:
 
1310
      {
 
1311
        meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1312
                       META_CORE_GET_FRAME_FLAGS, &flags,
 
1313
                       META_CORE_GET_END);
 
1314
        
 
1315
        if (flags & META_FRAME_ALLOWS_MAXIMIZE)
 
1316
          {
 
1317
            meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1318
          }
 
1319
      }
 
1320
      break;
 
1321
 
 
1322
    case META_ACTION_TITLEBAR_MINIMIZE:
 
1323
      {
 
1324
        meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1325
                       META_CORE_GET_FRAME_FLAGS, &flags,
 
1326
                       META_CORE_GET_END);
 
1327
        
 
1328
        if (flags & META_FRAME_ALLOWS_MINIMIZE)
 
1329
          {
 
1330
            meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1331
          }
 
1332
      }
 
1333
      break;
 
1334
 
 
1335
    case META_ACTION_TITLEBAR_NONE:
 
1336
      /* Yaay, a sane user that doesn't use that other weird crap! */
 
1337
      break;
 
1338
    
 
1339
    case META_ACTION_TITLEBAR_LOWER:
 
1340
      meta_core_user_lower_and_unfocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1341
                                        frame->xwindow,
 
1342
                                        event->time);
 
1343
      break;
 
1344
 
 
1345
    case META_ACTION_TITLEBAR_MENU:
 
1346
      meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1347
                                  frame->xwindow,
 
1348
                                  event->x_root,
 
1349
                                  event->y_root,
 
1350
                                  event->button,
 
1351
                                  event->time);
 
1352
      break;
 
1353
 
 
1354
    case META_ACTION_TITLEBAR_LAST:
 
1355
      break;
 
1356
    }
 
1357
  
 
1358
  return TRUE;
 
1359
}
 
1360
 
 
1361
static gboolean
 
1362
meta_frame_double_click_event (MetaUIFrame    *frame,
 
1363
                               GdkEventButton *event)
 
1364
{
 
1365
  int action = meta_prefs_get_action_double_click_titlebar ();
 
1366
  
 
1367
  return meta_frame_titlebar_event (frame, event, action);
 
1368
}
 
1369
 
 
1370
static gboolean
 
1371
meta_frame_middle_click_event (MetaUIFrame    *frame,
 
1372
                               GdkEventButton *event)
 
1373
{
 
1374
  int action = meta_prefs_get_action_middle_click_titlebar();
 
1375
  
 
1376
  return meta_frame_titlebar_event (frame, event, action);
 
1377
}
 
1378
 
 
1379
static gboolean
 
1380
meta_frame_right_click_event(MetaUIFrame     *frame,
 
1381
                             GdkEventButton  *event)
 
1382
{
 
1383
  int action = meta_prefs_get_action_right_click_titlebar();
 
1384
  
 
1385
  return meta_frame_titlebar_event (frame, event, action);
 
1386
}
 
1387
 
 
1388
static gboolean
 
1389
meta_frames_button_press_event (GtkWidget      *widget,
 
1390
                                GdkEventButton *event)
 
1391
{
 
1392
  MetaUIFrame *frame;
 
1393
  MetaFrames *frames;
 
1394
  MetaFrameControl control;
 
1395
  
 
1396
  frames = META_FRAMES (widget);
 
1397
 
 
1398
  /* Remember that the display may have already done something with this event.
 
1399
   * If so there's probably a GrabOp in effect.
 
1400
   */
 
1401
  
 
1402
  frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
 
1403
  if (frame == NULL)
 
1404
    return FALSE;
 
1405
 
 
1406
  clear_tip (frames);
 
1407
  
 
1408
  control = get_control (frames, frame, event->x, event->y);
 
1409
 
 
1410
  /* focus on click, even if click was on client area */
 
1411
  if (event->button == 1 &&
 
1412
      !(control == META_FRAME_CONTROL_MINIMIZE ||
 
1413
        control == META_FRAME_CONTROL_DELETE ||
 
1414
        control == META_FRAME_CONTROL_MAXIMIZE))
 
1415
    {
 
1416
      meta_topic (META_DEBUG_FOCUS,
 
1417
                  "Focusing window with frame 0x%lx due to button 1 press\n",
 
1418
                  frame->xwindow);
 
1419
      meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1420
                            frame->xwindow,
 
1421
                            event->time);      
 
1422
    }
 
1423
 
 
1424
  /* don't do the rest of this if on client area */
 
1425
  if (control == META_FRAME_CONTROL_CLIENT_AREA)
 
1426
    return FALSE; /* not on the frame, just passed through from client */
 
1427
  
 
1428
  /* We want to shade even if we have a GrabOp, since we'll have a move grab
 
1429
   * if we double click the titlebar.
 
1430
   */
 
1431
  if (control == META_FRAME_CONTROL_TITLE &&
 
1432
      event->button == 1 &&
 
1433
      event->type == GDK_2BUTTON_PRESS)
 
1434
    {
 
1435
      meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1436
      return meta_frame_double_click_event (frame, event);
 
1437
    }
 
1438
 
 
1439
  if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())) !=
 
1440
      META_GRAB_OP_NONE)
 
1441
    return FALSE; /* already up to something */  
 
1442
 
 
1443
  if (event->button == 1 &&
 
1444
      (control == META_FRAME_CONTROL_MAXIMIZE ||
 
1445
       control == META_FRAME_CONTROL_UNMAXIMIZE ||
 
1446
       control == META_FRAME_CONTROL_MINIMIZE ||
 
1447
       control == META_FRAME_CONTROL_DELETE ||
 
1448
       control == META_FRAME_CONTROL_SHADE ||
 
1449
       control == META_FRAME_CONTROL_UNSHADE ||
 
1450
       control == META_FRAME_CONTROL_ABOVE ||
 
1451
       control == META_FRAME_CONTROL_UNABOVE ||
 
1452
       control == META_FRAME_CONTROL_STICK ||
 
1453
       control == META_FRAME_CONTROL_UNSTICK ||
 
1454
       control == META_FRAME_CONTROL_MENU))
 
1455
    {
 
1456
      MetaGrabOp op = META_GRAB_OP_NONE;
 
1457
 
 
1458
      switch (control)
 
1459
        {
 
1460
        case META_FRAME_CONTROL_MINIMIZE:
 
1461
          op = META_GRAB_OP_CLICKING_MINIMIZE;
 
1462
          break;
 
1463
        case META_FRAME_CONTROL_MAXIMIZE:
 
1464
          op = META_GRAB_OP_CLICKING_MAXIMIZE;
 
1465
          break;
 
1466
        case META_FRAME_CONTROL_UNMAXIMIZE:
 
1467
          op = META_GRAB_OP_CLICKING_UNMAXIMIZE;
 
1468
          break;
 
1469
        case META_FRAME_CONTROL_DELETE:
 
1470
          op = META_GRAB_OP_CLICKING_DELETE;
 
1471
          break;
 
1472
        case META_FRAME_CONTROL_MENU:
 
1473
          op = META_GRAB_OP_CLICKING_MENU;
 
1474
          break;
 
1475
        case META_FRAME_CONTROL_SHADE:
 
1476
          op = META_GRAB_OP_CLICKING_SHADE;
 
1477
          break;
 
1478
        case META_FRAME_CONTROL_UNSHADE:
 
1479
          op = META_GRAB_OP_CLICKING_UNSHADE;
 
1480
          break;
 
1481
        case META_FRAME_CONTROL_ABOVE:
 
1482
          op = META_GRAB_OP_CLICKING_ABOVE;
 
1483
          break;
 
1484
        case META_FRAME_CONTROL_UNABOVE:
 
1485
          op = META_GRAB_OP_CLICKING_UNABOVE;
 
1486
          break;
 
1487
        case META_FRAME_CONTROL_STICK:
 
1488
          op = META_GRAB_OP_CLICKING_STICK;
 
1489
          break;
 
1490
        case META_FRAME_CONTROL_UNSTICK:
 
1491
          op = META_GRAB_OP_CLICKING_UNSTICK;
 
1492
          break;
 
1493
        default:
 
1494
          g_assert_not_reached ();
 
1495
          break;
 
1496
        }
 
1497
 
 
1498
      meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1499
                               frame->xwindow,
 
1500
                               op,
 
1501
                               TRUE,
 
1502
                               TRUE,
 
1503
                               event->button,
 
1504
                               0,
 
1505
                               event->time,
 
1506
                               event->x_root,
 
1507
                               event->y_root);      
 
1508
      
 
1509
      frame->prelit_control = control;
 
1510
      redraw_control (frames, frame, control);
 
1511
 
 
1512
      if (op == META_GRAB_OP_CLICKING_MENU)
 
1513
        {
 
1514
          MetaFrameGeometry fgeom;
 
1515
          GdkRectangle *rect;
 
1516
          int dx, dy;
 
1517
          
 
1518
          meta_frames_calc_geometry (frames, frame, &fgeom);
 
1519
          
 
1520
          rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
 
1521
 
 
1522
          /* get delta to convert to root coords */
 
1523
          dx = event->x_root - event->x;
 
1524
          dy = event->y_root - event->y;
 
1525
          
 
1526
          /* Align to the right end of the menu rectangle if RTL */
 
1527
          if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
 
1528
            dx += rect->width;
 
1529
 
 
1530
          meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1531
                                      frame->xwindow,
 
1532
                                      rect->x + dx,
 
1533
                                      rect->y + rect->height + dy,
 
1534
                                      event->button,
 
1535
                                      event->time);
 
1536
        }
 
1537
    }
 
1538
  else if (event->button == 1 &&
 
1539
           (control == META_FRAME_CONTROL_RESIZE_SE ||
 
1540
            control == META_FRAME_CONTROL_RESIZE_S ||
 
1541
            control == META_FRAME_CONTROL_RESIZE_SW ||
 
1542
            control == META_FRAME_CONTROL_RESIZE_NE ||
 
1543
            control == META_FRAME_CONTROL_RESIZE_N ||
 
1544
            control == META_FRAME_CONTROL_RESIZE_NW ||
 
1545
            control == META_FRAME_CONTROL_RESIZE_E ||
 
1546
            control == META_FRAME_CONTROL_RESIZE_W))
 
1547
    {
 
1548
      MetaGrabOp op;
 
1549
      gboolean titlebar_is_onscreen;
 
1550
      
 
1551
      op = META_GRAB_OP_NONE;
 
1552
      
 
1553
      switch (control)
 
1554
        {
 
1555
        case META_FRAME_CONTROL_RESIZE_SE:
 
1556
          op = META_GRAB_OP_RESIZING_SE;
 
1557
          break;
 
1558
        case META_FRAME_CONTROL_RESIZE_S:
 
1559
          op = META_GRAB_OP_RESIZING_S;
 
1560
          break;
 
1561
        case META_FRAME_CONTROL_RESIZE_SW:
 
1562
          op = META_GRAB_OP_RESIZING_SW;
 
1563
          break;
 
1564
        case META_FRAME_CONTROL_RESIZE_NE:
 
1565
          op = META_GRAB_OP_RESIZING_NE;
 
1566
          break;
 
1567
        case META_FRAME_CONTROL_RESIZE_N:
 
1568
          op = META_GRAB_OP_RESIZING_N;
 
1569
          break;
 
1570
        case META_FRAME_CONTROL_RESIZE_NW:
 
1571
          op = META_GRAB_OP_RESIZING_NW;
 
1572
          break;
 
1573
        case META_FRAME_CONTROL_RESIZE_E:
 
1574
          op = META_GRAB_OP_RESIZING_E;
 
1575
          break;
 
1576
        case META_FRAME_CONTROL_RESIZE_W:
 
1577
          op = META_GRAB_OP_RESIZING_W;
 
1578
          break;
 
1579
        default:
 
1580
          g_assert_not_reached ();
 
1581
          break;
 
1582
        }
 
1583
 
 
1584
      meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1585
                     META_CORE_IS_TITLEBAR_ONSCREEN, &titlebar_is_onscreen,
 
1586
                     META_CORE_GET_END);
 
1587
 
 
1588
      if (!titlebar_is_onscreen)
 
1589
        meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1590
                                    frame->xwindow,
 
1591
                                    event->x_root,
 
1592
                                    event->y_root,
 
1593
                                    event->button,
 
1594
                                    event->time);
 
1595
      else
 
1596
        meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1597
                                 frame->xwindow,
 
1598
                                 op,
 
1599
                                 TRUE,
 
1600
                                 TRUE,
 
1601
                                 event->button,
 
1602
                                 0,
 
1603
                                 event->time,
 
1604
                                 event->x_root,
 
1605
                                 event->y_root);
 
1606
    }
 
1607
  else if (control == META_FRAME_CONTROL_TITLE &&
 
1608
           event->button == 1)
 
1609
    {
 
1610
      MetaFrameFlags flags;
 
1611
 
 
1612
      meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
1613
                     META_CORE_GET_FRAME_FLAGS, &flags,
 
1614
                     META_CORE_GET_END);
 
1615
 
 
1616
      if (flags & META_FRAME_ALLOWS_MOVE)
 
1617
        {          
 
1618
          meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1619
                                   frame->xwindow,
 
1620
                                   META_GRAB_OP_MOVING,
 
1621
                                   TRUE,
 
1622
                                   TRUE,
 
1623
                                   event->button,
 
1624
                                   0,
 
1625
                                   event->time,
 
1626
                                   event->x_root,
 
1627
                                   event->y_root);
 
1628
        }
 
1629
    }
 
1630
  else if (event->button == 2)
 
1631
    {
 
1632
      return meta_frame_middle_click_event (frame, event);
 
1633
    }
 
1634
  else if (event->button == 3)
 
1635
    {
 
1636
      return meta_frame_right_click_event (frame, event);
 
1637
    }
 
1638
  
 
1639
  return TRUE;
 
1640
}
 
1641
 
 
1642
void
 
1643
meta_frames_notify_menu_hide (MetaFrames *frames)
 
1644
{
 
1645
  if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())) ==
 
1646
      META_GRAB_OP_CLICKING_MENU)
 
1647
    {
 
1648
      Window grab_frame;
 
1649
 
 
1650
      grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
 
1651
 
 
1652
      if (grab_frame != None)
 
1653
        {
 
1654
          MetaUIFrame *frame;
 
1655
 
 
1656
          frame = meta_frames_lookup_window (frames, grab_frame);
 
1657
 
 
1658
          if (frame)
 
1659
            {
 
1660
              redraw_control (frames, frame,
 
1661
                              META_FRAME_CONTROL_MENU);
 
1662
              meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), CurrentTime);
 
1663
            }
 
1664
        }
 
1665
    }
 
1666
}
 
1667
 
 
1668
static gboolean
 
1669
meta_frames_button_release_event    (GtkWidget           *widget,
 
1670
                                     GdkEventButton      *event)
 
1671
{
 
1672
  MetaUIFrame *frame;
 
1673
  MetaFrames *frames;
 
1674
  MetaGrabOp op;
 
1675
  
 
1676
  frames = META_FRAMES (widget);
 
1677
  
 
1678
  frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
 
1679
  if (frame == NULL)
 
1680
    return FALSE;
 
1681
 
 
1682
  clear_tip (frames);
 
1683
 
 
1684
  op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
 
1685
 
 
1686
  if (op == META_GRAB_OP_NONE)
 
1687
    return FALSE;
 
1688
 
 
1689
  /* We only handle the releases we handled the presses for (things
 
1690
   * involving frame controls). Window ops that don't require a
 
1691
   * frame are handled in the Xlib part of the code, display.c/window.c
 
1692
   */
 
1693
  if (frame->xwindow == meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())) &&
 
1694
      ((int) event->button) == meta_core_get_grab_button (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())))
 
1695
    {
 
1696
      MetaFrameControl control;
 
1697
 
 
1698
      control = get_control (frames, frame, event->x, event->y);
 
1699
      
 
1700
      switch (op)
 
1701
        {
 
1702
        case META_GRAB_OP_CLICKING_MINIMIZE:
 
1703
          if (control == META_FRAME_CONTROL_MINIMIZE)
 
1704
            meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1705
          
 
1706
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1707
          break;
 
1708
 
 
1709
        case META_GRAB_OP_CLICKING_MAXIMIZE:
 
1710
          if (control == META_FRAME_CONTROL_MAXIMIZE)
 
1711
          {
 
1712
            /* Focus the window on the maximize */
 
1713
            meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1714
                            frame->xwindow,
 
1715
                            event->time);      
 
1716
            meta_core_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1717
          }
 
1718
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1719
          break;
 
1720
 
 
1721
        case META_GRAB_OP_CLICKING_UNMAXIMIZE:
 
1722
          if (control == META_FRAME_CONTROL_UNMAXIMIZE)
 
1723
            meta_core_unmaximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1724
          
 
1725
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1726
          break;
 
1727
          
 
1728
        case META_GRAB_OP_CLICKING_DELETE:
 
1729
          if (control == META_FRAME_CONTROL_DELETE)
 
1730
            meta_core_delete (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, event->time);
 
1731
          
 
1732
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1733
          break;
 
1734
          
 
1735
        case META_GRAB_OP_CLICKING_MENU:
 
1736
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1737
          break;
 
1738
 
 
1739
        case META_GRAB_OP_CLICKING_SHADE:
 
1740
          if (control == META_FRAME_CONTROL_SHADE)
 
1741
            meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, event->time);
 
1742
          
 
1743
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1744
          break;
 
1745
 
 
1746
        case META_GRAB_OP_CLICKING_UNSHADE:
 
1747
          if (control == META_FRAME_CONTROL_UNSHADE)
 
1748
            meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, event->time);
 
1749
 
 
1750
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1751
          break;
 
1752
 
 
1753
        case META_GRAB_OP_CLICKING_ABOVE:
 
1754
          if (control == META_FRAME_CONTROL_ABOVE)
 
1755
            meta_core_make_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1756
          
 
1757
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1758
          break;
 
1759
 
 
1760
        case META_GRAB_OP_CLICKING_UNABOVE:
 
1761
          if (control == META_FRAME_CONTROL_UNABOVE)
 
1762
            meta_core_unmake_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1763
 
 
1764
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1765
          break;
 
1766
 
 
1767
        case META_GRAB_OP_CLICKING_STICK:
 
1768
          if (control == META_FRAME_CONTROL_STICK)
 
1769
            meta_core_stick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1770
 
 
1771
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1772
          break;
 
1773
 
 
1774
        case META_GRAB_OP_CLICKING_UNSTICK:
 
1775
          if (control == META_FRAME_CONTROL_UNSTICK)
 
1776
            meta_core_unstick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
 
1777
 
 
1778
          meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
 
1779
          break;
 
1780
          
 
1781
        default:
 
1782
          break;
 
1783
        }
 
1784
 
 
1785
      /* Update the prelit control regardless of what button the mouse
 
1786
       * was released over; needed so that the new button can become
 
1787
       * prelit so to let the user know that it can now be pressed.
 
1788
       * :)
 
1789
       */
 
1790
      meta_frames_update_prelit_control (frames, frame, control);
 
1791
    }
 
1792
  
 
1793
  return TRUE;
 
1794
}
 
1795
 
 
1796
static void
 
1797
meta_frames_update_prelit_control (MetaFrames      *frames,
 
1798
                                   MetaUIFrame     *frame,
 
1799
                                   MetaFrameControl control)
 
1800
{
 
1801
  MetaFrameControl old_control;
 
1802
  MetaCursor cursor;
 
1803
 
 
1804
 
 
1805
  meta_verbose ("Updating prelit control from %u to %u\n",
 
1806
                frame->prelit_control, control);
 
1807
  
 
1808
  cursor = META_CURSOR_DEFAULT;
 
1809
  
 
1810
  switch (control)
 
1811
    {
 
1812
    case META_FRAME_CONTROL_CLIENT_AREA:
 
1813
      break;
 
1814
    case META_FRAME_CONTROL_NONE:
 
1815
      break;
 
1816
    case META_FRAME_CONTROL_TITLE:
 
1817
      break;
 
1818
    case META_FRAME_CONTROL_DELETE:
 
1819
      break;
 
1820
    case META_FRAME_CONTROL_MENU:
 
1821
      break;
 
1822
    case META_FRAME_CONTROL_MINIMIZE:
 
1823
      break;
 
1824
    case META_FRAME_CONTROL_MAXIMIZE:
 
1825
      break;
 
1826
    case META_FRAME_CONTROL_UNMAXIMIZE:
 
1827
      break;
 
1828
    case META_FRAME_CONTROL_SHADE:
 
1829
      break;
 
1830
    case META_FRAME_CONTROL_UNSHADE:
 
1831
      break;
 
1832
    case META_FRAME_CONTROL_ABOVE:
 
1833
      break;
 
1834
    case META_FRAME_CONTROL_UNABOVE:
 
1835
      break;
 
1836
    case META_FRAME_CONTROL_STICK:
 
1837
      break;
 
1838
    case META_FRAME_CONTROL_UNSTICK:
 
1839
      break;
 
1840
    case META_FRAME_CONTROL_RESIZE_SE:
 
1841
      cursor = META_CURSOR_SE_RESIZE;
 
1842
      break;
 
1843
    case META_FRAME_CONTROL_RESIZE_S:
 
1844
      cursor = META_CURSOR_SOUTH_RESIZE;
 
1845
      break;
 
1846
    case META_FRAME_CONTROL_RESIZE_SW:
 
1847
      cursor = META_CURSOR_SW_RESIZE;
 
1848
      break;
 
1849
    case META_FRAME_CONTROL_RESIZE_N:
 
1850
      cursor = META_CURSOR_NORTH_RESIZE;
 
1851
      break;
 
1852
    case META_FRAME_CONTROL_RESIZE_NE:
 
1853
      cursor = META_CURSOR_NE_RESIZE;
 
1854
      break;
 
1855
    case META_FRAME_CONTROL_RESIZE_NW:
 
1856
      cursor = META_CURSOR_NW_RESIZE;
 
1857
      break;
 
1858
    case META_FRAME_CONTROL_RESIZE_W:
 
1859
      cursor = META_CURSOR_WEST_RESIZE;
 
1860
      break;
 
1861
    case META_FRAME_CONTROL_RESIZE_E:
 
1862
      cursor = META_CURSOR_EAST_RESIZE;
 
1863
      break;
 
1864
    }        
 
1865
 
 
1866
  /* set/unset the prelight cursor */
 
1867
  meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
 
1868
                               frame->xwindow,
 
1869
                               cursor);  
 
1870
 
 
1871
  switch (control)
 
1872
    {
 
1873
    case META_FRAME_CONTROL_MENU:
 
1874
    case META_FRAME_CONTROL_MINIMIZE:
 
1875
    case META_FRAME_CONTROL_MAXIMIZE:
 
1876
    case META_FRAME_CONTROL_DELETE:
 
1877
    case META_FRAME_CONTROL_SHADE:
 
1878
    case META_FRAME_CONTROL_UNSHADE:
 
1879
    case META_FRAME_CONTROL_ABOVE:
 
1880
    case META_FRAME_CONTROL_UNABOVE:
 
1881
    case META_FRAME_CONTROL_STICK:
 
1882
    case META_FRAME_CONTROL_UNSTICK:
 
1883
    case META_FRAME_CONTROL_UNMAXIMIZE:
 
1884
      /* leave control set */
 
1885
      break;
 
1886
    default:
 
1887
      /* Only prelight buttons */
 
1888
      control = META_FRAME_CONTROL_NONE;
 
1889
      break;
 
1890
    }      
 
1891
 
 
1892
  if (control == frame->prelit_control)
 
1893
    return;
 
1894
 
 
1895
  /* Save the old control so we can unprelight it */
 
1896
  old_control = frame->prelit_control;
 
1897
 
 
1898
  frame->prelit_control = control;
 
1899
 
 
1900
  redraw_control (frames, frame, old_control);
 
1901
  redraw_control (frames, frame, control);
 
1902
}
 
1903
 
 
1904
static gboolean
 
1905
meta_frames_motion_notify_event     (GtkWidget           *widget,
 
1906
                                     GdkEventMotion      *event)
 
1907
{
 
1908
  MetaUIFrame *frame;
 
1909
  MetaFrames *frames;
 
1910
  MetaGrabOp grab_op;
 
1911
  
 
1912
  frames = META_FRAMES (widget);
 
1913
  
 
1914
  frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
 
1915
  if (frame == NULL)
 
1916
    return FALSE;
 
1917
 
 
1918
  clear_tip (frames);
 
1919
 
 
1920
  frames->last_motion_frame = frame;
 
1921
 
 
1922
  grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
 
1923
  
 
1924
  switch (grab_op)
 
1925
    {
 
1926
    case META_GRAB_OP_CLICKING_MENU:
 
1927
    case META_GRAB_OP_CLICKING_DELETE:
 
1928
    case META_GRAB_OP_CLICKING_MINIMIZE:
 
1929
    case META_GRAB_OP_CLICKING_MAXIMIZE:
 
1930
    case META_GRAB_OP_CLICKING_UNMAXIMIZE:
 
1931
    case META_GRAB_OP_CLICKING_SHADE:
 
1932
    case META_GRAB_OP_CLICKING_UNSHADE:
 
1933
    case META_GRAB_OP_CLICKING_ABOVE:
 
1934
    case META_GRAB_OP_CLICKING_UNABOVE:
 
1935
    case META_GRAB_OP_CLICKING_STICK:
 
1936
    case META_GRAB_OP_CLICKING_UNSTICK:
 
1937
      {
 
1938
        MetaFrameControl control;
 
1939
        int x, y;
 
1940
        
 
1941
        gdk_window_get_pointer (frame->window, &x, &y, NULL);
 
1942
 
 
1943
        /* Control is set to none unless it matches
 
1944
         * the current grab
 
1945
         */
 
1946
        control = get_control (frames, frame, x, y);
 
1947
        if (! ((control == META_FRAME_CONTROL_MENU &&
 
1948
                grab_op == META_GRAB_OP_CLICKING_MENU) ||
 
1949
               (control == META_FRAME_CONTROL_DELETE &&
 
1950
                grab_op == META_GRAB_OP_CLICKING_DELETE) ||
 
1951
               (control == META_FRAME_CONTROL_MINIMIZE &&
 
1952
                grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
 
1953
               ((control == META_FRAME_CONTROL_MAXIMIZE ||
 
1954
                 control == META_FRAME_CONTROL_UNMAXIMIZE) &&
 
1955
                (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
 
1956
                 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)) ||
 
1957
               (control == META_FRAME_CONTROL_SHADE &&
 
1958
                grab_op == META_GRAB_OP_CLICKING_SHADE) ||
 
1959
               (control == META_FRAME_CONTROL_UNSHADE &&
 
1960
                grab_op == META_GRAB_OP_CLICKING_UNSHADE) ||
 
1961
               (control == META_FRAME_CONTROL_ABOVE &&
 
1962
                grab_op == META_GRAB_OP_CLICKING_ABOVE) ||
 
1963
               (control == META_FRAME_CONTROL_UNABOVE &&
 
1964
                grab_op == META_GRAB_OP_CLICKING_UNABOVE) ||
 
1965
               (control == META_FRAME_CONTROL_STICK &&
 
1966
                grab_op == META_GRAB_OP_CLICKING_STICK) ||
 
1967
               (control == META_FRAME_CONTROL_UNSTICK &&
 
1968
                grab_op == META_GRAB_OP_CLICKING_UNSTICK)))
 
1969
           control = META_FRAME_CONTROL_NONE;
 
1970
        
 
1971
        /* Update prelit control and cursor */
 
1972
        meta_frames_update_prelit_control (frames, frame, control);
 
1973
 
 
1974
        /* No tooltip while in the process of clicking */
 
1975
      }
 
1976
      break;
 
1977
    case META_GRAB_OP_NONE:
 
1978
      {
 
1979
        MetaFrameControl control;
 
1980
        int x, y;
 
1981
        
 
1982
        gdk_window_get_pointer (frame->window, &x, &y, NULL);
 
1983
 
 
1984
        control = get_control (frames, frame, x, y);
 
1985
 
 
1986
        /* Update prelit control and cursor */
 
1987
        meta_frames_update_prelit_control (frames, frame, control);
 
1988
        
 
1989
        queue_tip (frames);
 
1990
      }
 
1991
      break;
 
1992
 
 
1993
    default:
 
1994
      break;
 
1995
    }
 
1996
      
 
1997
  return TRUE;
 
1998
}
 
1999
 
 
2000
static gboolean
 
2001
meta_frames_destroy_event           (GtkWidget           *widget,
 
2002
                                     GdkEventAny         *event)
 
2003
{
 
2004
  MetaUIFrame *frame;
 
2005
  MetaFrames *frames;
 
2006
 
 
2007
  frames = META_FRAMES (widget);
 
2008
 
 
2009
  frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
 
2010
  if (frame == NULL)
 
2011
    return FALSE;
 
2012
  
 
2013
  return TRUE;
 
2014
}
 
2015
 
 
2016
#if !GTK_CHECK_VERSION(2,21,6)
 
2017
/* Copied from GDK */
 
2018
static cairo_surface_t *
 
2019
_gdk_drawable_ref_cairo_surface (GdkDrawable *drawable)
 
2020
{
 
2021
  g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
 
2022
 
 
2023
  return GDK_DRAWABLE_GET_CLASS (drawable)->ref_cairo_surface (drawable);
 
2024
}
 
2025
 
 
2026
static cairo_pattern_t *
 
2027
gdk_window_get_background_pattern (GdkWindow *window)
 
2028
{
 
2029
  GdkWindowObject *private = (GdkWindowObject *) window;
 
2030
  cairo_pattern_t *pattern;
 
2031
 
 
2032
  g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
 
2033
 
 
2034
  if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG)
 
2035
    pattern = NULL;
 
2036
  else if (private->bg_pixmap != GDK_NO_BG &&
 
2037
           private->bg_pixmap != NULL)
 
2038
    {
 
2039
      static cairo_user_data_key_t key;
 
2040
      cairo_surface_t *surface;
 
2041
 
 
2042
      surface = _gdk_drawable_ref_cairo_surface (private->bg_pixmap);
 
2043
      pattern = cairo_pattern_create_for_surface (surface);
 
2044
      cairo_surface_destroy (surface);
 
2045
 
 
2046
      cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
 
2047
      cairo_pattern_set_user_data (pattern,
 
2048
                                   &key,
 
2049
                                   g_object_ref (private->bg_pixmap),
 
2050
                                   g_object_unref);
 
2051
    }
 
2052
  else
 
2053
    {
 
2054
      pattern =
 
2055
        cairo_pattern_create_rgb (private->bg_color.red   / 65535.,
 
2056
                                  private->bg_color.green / 65535.,
 
2057
                                  private->bg_color.blue / 65535.);
 
2058
    }
 
2059
 
 
2060
  return pattern;
 
2061
}
 
2062
#endif
 
2063
 
 
2064
static void
 
2065
setup_bg_cr (cairo_t *cr, GdkWindow *window, int x_offset, int y_offset)
 
2066
{
 
2067
  GdkWindow *parent = gdk_window_get_parent (window);
 
2068
  cairo_pattern_t *bg_pattern;
 
2069
 
 
2070
  bg_pattern = gdk_window_get_background_pattern (window);
 
2071
  if (bg_pattern == NULL && parent)
 
2072
    {
 
2073
      gint window_x, window_y;
 
2074
 
 
2075
      gdk_window_get_position (window, &window_x, &window_y);
 
2076
      setup_bg_cr (cr, parent, x_offset + window_x, y_offset + window_y);
 
2077
    }
 
2078
  else if (bg_pattern)
 
2079
    {
 
2080
      cairo_translate (cr, - x_offset, - y_offset);
 
2081
      cairo_set_source (cr, bg_pattern);
 
2082
      cairo_translate (cr, x_offset, y_offset);
 
2083
    }
 
2084
}
 
2085
 
 
2086
static void
 
2087
clear_backing (GdkPixmap *pixmap,
 
2088
               GdkWindow *window,
 
2089
               int xoffset, int yoffset)
 
2090
{
 
2091
  int width, height;
 
2092
  cairo_t *cr = gdk_cairo_create (pixmap);
 
2093
 
 
2094
  setup_bg_cr (cr, window, xoffset, yoffset);
 
2095
 
 
2096
  gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
 
2097
  cairo_rectangle (cr, 0, 0, width, height);
 
2098
  cairo_fill (cr);
 
2099
 
 
2100
  cairo_destroy (cr);
 
2101
}
 
2102
 
 
2103
/* Returns a pixmap with a piece of the windows frame painted on it.
 
2104
*/
 
2105
 
 
2106
static GdkPixmap *
 
2107
generate_pixmap (MetaFrames *frames,
 
2108
                 MetaUIFrame *frame,
 
2109
                 MetaRectangle rect)
 
2110
{
 
2111
  GdkRectangle rectangle;
 
2112
  GdkRegion *region;
 
2113
  GdkPixmap *result;
 
2114
 
 
2115
  rectangle.x = rect.x;
 
2116
  rectangle.y = rect.y;
 
2117
  rectangle.width = MAX (rect.width, 1);
 
2118
  rectangle.height = MAX (rect.height, 1);
 
2119
  
 
2120
  result = gdk_pixmap_new (frame->window,
 
2121
                           rectangle.width, rectangle.height, -1);
 
2122
  
 
2123
  clear_backing (result, frame->window, rectangle.x, rectangle.y);
 
2124
 
 
2125
  region = gdk_region_rectangle (&rectangle);
 
2126
 
 
2127
  meta_frames_paint_to_drawable (frames, frame, result, region,
 
2128
                                 -rectangle.x, -rectangle.y);
 
2129
 
 
2130
  gdk_region_destroy (region);
 
2131
 
 
2132
  return result;
 
2133
}
 
2134
 
 
2135
 
 
2136
static void
 
2137
populate_cache (MetaFrames *frames,
 
2138
                MetaUIFrame *frame)
 
2139
{
 
2140
  int top, bottom, left, right;
 
2141
  int width, height;
 
2142
  int frame_width, frame_height, screen_width, screen_height;
 
2143
  CachedPixels *pixels;
 
2144
  MetaFrameType frame_type;
 
2145
  MetaFrameFlags frame_flags;
 
2146
  int i;
 
2147
 
 
2148
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
2149
                 META_CORE_GET_FRAME_WIDTH, &frame_width,
 
2150
                 META_CORE_GET_FRAME_HEIGHT, &frame_height,
 
2151
                 META_CORE_GET_SCREEN_WIDTH, &screen_width,
 
2152
                 META_CORE_GET_SCREEN_HEIGHT, &screen_height,
 
2153
                 META_CORE_GET_CLIENT_WIDTH, &width,
 
2154
                 META_CORE_GET_CLIENT_HEIGHT, &height,
 
2155
                 META_CORE_GET_FRAME_TYPE, &frame_type,
 
2156
                 META_CORE_GET_FRAME_FLAGS, &frame_flags,
 
2157
                 META_CORE_GET_END);
 
2158
 
 
2159
  /* don't cache extremely large windows */
 
2160
  if (frame_width > 2 * screen_width ||
 
2161
      frame_height > 2 * screen_height)
 
2162
    {
 
2163
      return;
 
2164
    }
 
2165
  
 
2166
  meta_theme_get_frame_borders (meta_theme_get_current (),
 
2167
                                frame_type,
 
2168
                                frame->text_height,
 
2169
                                frame_flags,
 
2170
                                &top, &bottom, &left, &right);
 
2171
 
 
2172
  pixels = get_cache (frames, frame);
 
2173
 
 
2174
  /* Setup the rectangles for the four frame borders. First top, then
 
2175
     left, right and bottom. */
 
2176
  pixels->piece[0].rect.x = 0;
 
2177
  pixels->piece[0].rect.y = 0;
 
2178
  pixels->piece[0].rect.width = left + width + right;
 
2179
  pixels->piece[0].rect.height = top;
 
2180
 
 
2181
  pixels->piece[1].rect.x = 0;
 
2182
  pixels->piece[1].rect.y = top;
 
2183
  pixels->piece[1].rect.width = left;
 
2184
  pixels->piece[1].rect.height = height;
 
2185
 
 
2186
  pixels->piece[2].rect.x = left + width;
 
2187
  pixels->piece[2].rect.y = top;
 
2188
  pixels->piece[2].rect.width = right;
 
2189
  pixels->piece[2].rect.height = height;
 
2190
 
 
2191
  pixels->piece[3].rect.x = 0;
 
2192
  pixels->piece[3].rect.y = top + height;
 
2193
  pixels->piece[3].rect.width = left + width + right;
 
2194
  pixels->piece[3].rect.height = bottom;
 
2195
 
 
2196
  for (i = 0; i < 4; i++)
 
2197
    {
 
2198
      CachedFramePiece *piece = &pixels->piece[i];
 
2199
      if (!piece->pixmap)
 
2200
        piece->pixmap = generate_pixmap (frames, frame, piece->rect);
 
2201
    }
 
2202
  
 
2203
  if (frames->invalidate_cache_timeout_id)
 
2204
    g_source_remove (frames->invalidate_cache_timeout_id);
 
2205
  
 
2206
  frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames);
 
2207
 
 
2208
  if (!g_list_find (frames->invalidate_frames, frame))
 
2209
    frames->invalidate_frames =
 
2210
      g_list_prepend (frames->invalidate_frames, frame);
 
2211
}
 
2212
 
 
2213
static void
 
2214
clip_to_screen (GdkRegion *region, MetaUIFrame *frame)
 
2215
{
 
2216
  GdkRectangle frame_area;
 
2217
  GdkRectangle screen_area = { 0, 0, 0, 0 };
 
2218
  GdkRegion *tmp_region;
 
2219
  
 
2220
  /* Chop off stuff outside the screen; this optimization
 
2221
   * is crucial to handle huge client windows,
 
2222
   * like "xterm -geometry 1000x1000"
 
2223
   */
 
2224
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
2225
                 META_CORE_GET_FRAME_X, &frame_area.x,
 
2226
                 META_CORE_GET_FRAME_Y, &frame_area.y,
 
2227
                 META_CORE_GET_FRAME_WIDTH, &frame_area.width,
 
2228
                 META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
 
2229
                 META_CORE_GET_SCREEN_WIDTH, &screen_area.height,
 
2230
                 META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
 
2231
                 META_CORE_GET_END);
 
2232
 
 
2233
  gdk_region_offset (region, frame_area.x, frame_area.y);
 
2234
 
 
2235
  tmp_region = gdk_region_rectangle (&frame_area);
 
2236
  gdk_region_intersect (region, tmp_region);
 
2237
  gdk_region_destroy (tmp_region);
 
2238
 
 
2239
  gdk_region_offset (region, - frame_area.x, - frame_area.y);
 
2240
}
 
2241
 
 
2242
static void
 
2243
subtract_from_region (GdkRegion *region, GdkDrawable *drawable,
 
2244
                      gint x, gint y)
 
2245
{
 
2246
  GdkRectangle rect;
 
2247
  GdkRegion *reg_rect;
 
2248
 
 
2249
  gdk_drawable_get_size (drawable, &rect.width, &rect.height);
 
2250
  rect.x = x;
 
2251
  rect.y = y;
 
2252
 
 
2253
  reg_rect = gdk_region_rectangle (&rect);
 
2254
  gdk_region_subtract (region, reg_rect);
 
2255
  gdk_region_destroy (reg_rect);
 
2256
}
 
2257
 
 
2258
static void
 
2259
cached_pixels_draw (CachedPixels *pixels,
 
2260
                    GdkWindow *window,
 
2261
                    GdkRegion *region)
 
2262
{
 
2263
  cairo_t *cr;
 
2264
  int i;
 
2265
 
 
2266
  cr = gdk_cairo_create (window);
 
2267
 
 
2268
  for (i = 0; i < 4; i++)
 
2269
    {
 
2270
      CachedFramePiece *piece;
 
2271
      piece = &pixels->piece[i];
 
2272
      
 
2273
      if (piece->pixmap)
 
2274
        {
 
2275
          gdk_cairo_set_source_pixmap (cr, piece->pixmap,
 
2276
                                       piece->rect.x, piece->rect.y);
 
2277
          cairo_paint (cr);
 
2278
          subtract_from_region (region, piece->pixmap,
 
2279
          piece->rect.x, piece->rect.y);
 
2280
        }
 
2281
    }
 
2282
  
 
2283
  cairo_destroy (cr);
 
2284
}
 
2285
 
 
2286
static gboolean
 
2287
meta_frames_expose_event (GtkWidget           *widget,
 
2288
                          GdkEventExpose      *event)
 
2289
{
 
2290
  MetaUIFrame *frame;
 
2291
  MetaFrames *frames;
 
2292
  GdkRegion *region;
 
2293
  CachedPixels *pixels;
 
2294
 
 
2295
  frames = META_FRAMES (widget);
 
2296
 
 
2297
  frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
 
2298
  if (frame == NULL)
 
2299
    return FALSE;
 
2300
 
 
2301
  if (frames->expose_delay_count > 0)
 
2302
    {
 
2303
      /* Redraw this entire frame later */
 
2304
      frame->expose_delayed = TRUE;
 
2305
      return TRUE;
 
2306
    }
 
2307
 
 
2308
  populate_cache (frames, frame);
 
2309
 
 
2310
  region = gdk_region_copy (event->region);
 
2311
  
 
2312
  pixels = get_cache (frames, frame);
 
2313
 
 
2314
  cached_pixels_draw (pixels, frame->window, region);
 
2315
  
 
2316
  clip_to_screen (region, frame);
 
2317
  meta_frames_paint_to_drawable (frames, frame, frame->window, region, 0, 0);
 
2318
 
 
2319
  gdk_region_destroy (region);
 
2320
  
 
2321
  return TRUE;
 
2322
}
 
2323
 
 
2324
/* How far off the screen edge the window decorations should
 
2325
 * be drawn. Used only in meta_frames_paint_to_drawable, below.
 
2326
 */
 
2327
#define DECORATING_BORDER 100
 
2328
 
 
2329
static void
 
2330
meta_frames_paint_to_drawable (MetaFrames   *frames,
 
2331
                               MetaUIFrame  *frame,
 
2332
                               GdkDrawable  *drawable,
 
2333
                               GdkRegion    *region,
 
2334
                               int           x_offset,
 
2335
                               int           y_offset)
 
2336
{
 
2337
  GtkWidget *widget;
 
2338
  MetaFrameFlags flags;
 
2339
  MetaFrameType type;
 
2340
  GdkPixbuf *mini_icon;
 
2341
  GdkPixbuf *icon;
 
2342
  int w, h;
 
2343
  MetaButtonState button_states[META_BUTTON_TYPE_LAST];
 
2344
  Window grab_frame;
 
2345
  int i;
 
2346
  MetaButtonLayout button_layout;
 
2347
  MetaGrabOp grab_op;
 
2348
  
 
2349
  widget = GTK_WIDGET (frames);
 
2350
 
 
2351
  for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
 
2352
    button_states[i] = META_BUTTON_STATE_NORMAL;
 
2353
 
 
2354
  grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
 
2355
  grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
 
2356
  if (grab_frame != frame->xwindow)
 
2357
    grab_op = META_GRAB_OP_NONE;
 
2358
  
 
2359
  /* Set prelight state */
 
2360
  switch (frame->prelit_control)
 
2361
    {
 
2362
    case META_FRAME_CONTROL_MENU:
 
2363
      if (grab_op == META_GRAB_OP_CLICKING_MENU)
 
2364
        button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED;
 
2365
      else
 
2366
        button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT;
 
2367
      break;
 
2368
    case META_FRAME_CONTROL_MINIMIZE:
 
2369
      if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE)
 
2370
        button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED;
 
2371
      else
 
2372
        button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT;
 
2373
      break;
 
2374
    case META_FRAME_CONTROL_MAXIMIZE:
 
2375
      if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE)
 
2376
        button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
 
2377
      else
 
2378
        button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
 
2379
      break;
 
2380
    case META_FRAME_CONTROL_UNMAXIMIZE:
 
2381
      if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)
 
2382
        button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
 
2383
      else
 
2384
        button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
 
2385
      break;
 
2386
    case META_FRAME_CONTROL_SHADE:
 
2387
      if (grab_op == META_GRAB_OP_CLICKING_SHADE)
 
2388
        button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED;
 
2389
      else
 
2390
        button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT;
 
2391
      break;
 
2392
    case META_FRAME_CONTROL_UNSHADE:
 
2393
      if (grab_op == META_GRAB_OP_CLICKING_UNSHADE)
 
2394
        button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED;
 
2395
      else
 
2396
        button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT;
 
2397
      break;
 
2398
    case META_FRAME_CONTROL_ABOVE:
 
2399
      if (grab_op == META_GRAB_OP_CLICKING_ABOVE)
 
2400
        button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED;
 
2401
      else
 
2402
        button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT;
 
2403
      break;
 
2404
    case META_FRAME_CONTROL_UNABOVE:
 
2405
      if (grab_op == META_GRAB_OP_CLICKING_UNABOVE)
 
2406
        button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED;
 
2407
      else
 
2408
        button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT;
 
2409
      break;
 
2410
    case META_FRAME_CONTROL_STICK:
 
2411
      if (grab_op == META_GRAB_OP_CLICKING_STICK)
 
2412
        button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED;
 
2413
      else
 
2414
        button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT;
 
2415
      break;
 
2416
    case META_FRAME_CONTROL_UNSTICK:
 
2417
      if (grab_op == META_GRAB_OP_CLICKING_UNSTICK)
 
2418
        button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED;
 
2419
      else
 
2420
        button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT;
 
2421
      break;
 
2422
    case META_FRAME_CONTROL_DELETE:
 
2423
      if (grab_op == META_GRAB_OP_CLICKING_DELETE)
 
2424
        button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
 
2425
      else
 
2426
        button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT;
 
2427
      break;
 
2428
    default:
 
2429
      break;
 
2430
    }
 
2431
 
 
2432
  /* Map button function states to button position states */
 
2433
  button_states[META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND] =
 
2434
    button_states[META_BUTTON_TYPE_MENU];
 
2435
  button_states[META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND] =
 
2436
    META_BUTTON_STATE_NORMAL;
 
2437
  button_states[META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND] =
 
2438
    META_BUTTON_STATE_NORMAL;
 
2439
  button_states[META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND] =
 
2440
    button_states[META_BUTTON_TYPE_MINIMIZE];
 
2441
  button_states[META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND] =
 
2442
    button_states[META_BUTTON_TYPE_MAXIMIZE];
 
2443
  button_states[META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND] =
 
2444
    button_states[META_BUTTON_TYPE_CLOSE];
 
2445
  
 
2446
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
2447
                 META_CORE_GET_FRAME_FLAGS, &flags,
 
2448
                 META_CORE_GET_FRAME_TYPE, &type,
 
2449
                 META_CORE_GET_MINI_ICON, &mini_icon,
 
2450
                 META_CORE_GET_ICON, &icon,
 
2451
                 META_CORE_GET_CLIENT_WIDTH, &w,
 
2452
                 META_CORE_GET_CLIENT_HEIGHT, &h,
 
2453
                 META_CORE_GET_END);
 
2454
 
 
2455
  meta_frames_ensure_layout (frames, frame);
 
2456
 
 
2457
  meta_prefs_get_button_layout (&button_layout);
 
2458
 
 
2459
  if (G_LIKELY (GDK_IS_WINDOW (drawable)))
 
2460
    {
 
2461
      /* A window; happens about 2/3 of the time */
 
2462
 
 
2463
      GdkRectangle area, *areas;
 
2464
      int n_areas;
 
2465
      int screen_width, screen_height;
 
2466
      GdkRegion *edges, *tmp_region;
 
2467
      int top, bottom, left, right;
 
2468
 
 
2469
      /* Repaint each side of the frame */
 
2470
 
 
2471
      meta_theme_get_frame_borders (meta_theme_get_current (),
 
2472
                             type, frame->text_height, flags, 
 
2473
                             &top, &bottom, &left, &right);
 
2474
 
 
2475
      meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
2476
                     META_CORE_GET_SCREEN_WIDTH, &screen_width,
 
2477
                     META_CORE_GET_SCREEN_HEIGHT, &screen_height,
 
2478
                     META_CORE_GET_END);
 
2479
 
 
2480
      edges = gdk_region_copy (region);
 
2481
 
 
2482
      /* Punch out the client area */
 
2483
 
 
2484
      area.x = left;
 
2485
      area.y = top;
 
2486
      area.width = w;
 
2487
      area.height = h;
 
2488
      tmp_region = gdk_region_rectangle (&area);
 
2489
      gdk_region_subtract (edges, tmp_region);
 
2490
      gdk_region_destroy (tmp_region);
 
2491
 
 
2492
      /* Now draw remaining portion of region */
 
2493
 
 
2494
      gdk_region_get_rectangles (edges, &areas, &n_areas);
 
2495
 
 
2496
      for (i = 0; i < n_areas; i++)
 
2497
        {
 
2498
          /* Bug 399529: clamp areas[i] so that it doesn't go too far
 
2499
           * off the edge of the screen. This works around a GDK bug
 
2500
           * which makes gdk_window_begin_paint_rect cause an X error
 
2501
           * if the window is insanely huge. If the client is a GDK program
 
2502
           * and does this, it will still probably cause an X error in that
 
2503
           * program, but the last thing we want is for Metacity to crash
 
2504
           * because it attempted to decorate the silly window.
 
2505
           */
 
2506
 
 
2507
          areas[i].x = MAX (areas[i].x, -DECORATING_BORDER); 
 
2508
          areas[i].y = MAX (areas[i].y, -DECORATING_BORDER); 
 
2509
          if (areas[i].x+areas[i].width  > screen_width  + DECORATING_BORDER)
 
2510
            areas[i].width  = MIN (0, screen_width  - areas[i].x);
 
2511
          if (areas[i].y+areas[i].height > screen_height + DECORATING_BORDER)
 
2512
            areas[i].height = MIN (0, screen_height - areas[i].y);
 
2513
 
 
2514
          /* Okay, so let's start painting. */
 
2515
 
 
2516
          gdk_window_begin_paint_rect (drawable, &areas[i]);
 
2517
 
 
2518
          meta_theme_draw_frame_with_style (meta_theme_get_current (),
 
2519
            frame->style,
 
2520
            widget,
 
2521
            drawable,
 
2522
            NULL, /* &areas[i], */
 
2523
            x_offset, y_offset,
 
2524
            type,
 
2525
            flags,
 
2526
            w, h,
 
2527
            frame->layout,
 
2528
            frame->text_height,
 
2529
            &button_layout,
 
2530
            button_states,
 
2531
            mini_icon, icon);
 
2532
 
 
2533
          gdk_window_end_paint (drawable);
 
2534
        }
 
2535
 
 
2536
      g_free (areas);
 
2537
      gdk_region_destroy (edges);
 
2538
 
 
2539
    }
 
2540
  else
 
2541
    {
 
2542
      /* Not a window; happens about 1/3 of the time */
 
2543
 
 
2544
      meta_theme_draw_frame_with_style (meta_theme_get_current (),
 
2545
                                        frame->style,
 
2546
                                        widget,
 
2547
                                        drawable,
 
2548
                                        NULL,
 
2549
                                        x_offset, y_offset,
 
2550
                                        type,
 
2551
                                        flags,
 
2552
                                        w, h,
 
2553
                                        frame->layout,
 
2554
                                        frame->text_height,
 
2555
                                        &button_layout,
 
2556
                                        button_states,
 
2557
                                        mini_icon, icon);
 
2558
    }
 
2559
 
 
2560
}
 
2561
 
 
2562
static void
 
2563
meta_frames_set_window_background (MetaFrames   *frames,
 
2564
                                   MetaUIFrame  *frame)
 
2565
{
 
2566
  MetaFrameFlags flags;
 
2567
  MetaFrameType type;
 
2568
  MetaFrameStyle *style;
 
2569
  gboolean frame_exists;
 
2570
 
 
2571
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
2572
                 META_CORE_WINDOW_HAS_FRAME, &frame_exists,
 
2573
                 META_CORE_GET_FRAME_FLAGS, &flags,
 
2574
                 META_CORE_GET_FRAME_TYPE, &type,
 
2575
                 META_CORE_GET_END);
 
2576
 
 
2577
  if (frame_exists)
 
2578
    {
 
2579
      style = meta_theme_get_frame_style (meta_theme_get_current (),
 
2580
                                          type, flags);
 
2581
    }
 
2582
 
 
2583
  if (frame_exists && style->window_background_color != NULL)
 
2584
    {
 
2585
      GdkColor color;
 
2586
      GdkVisual *visual;
 
2587
 
 
2588
      meta_color_spec_render (style->window_background_color,
 
2589
                              GTK_WIDGET (frames),
 
2590
                              &color);
 
2591
 
 
2592
      /* Set A in ARGB to window_background_alpha, if we have ARGB */
 
2593
 
 
2594
      visual = gtk_widget_get_visual (GTK_WIDGET (frames));
 
2595
      if (visual->depth == 32) /* we have ARGB */
 
2596
        {
 
2597
          color.pixel = (color.pixel & 0xffffff) &
 
2598
            style->window_background_alpha << 24;
 
2599
        }
 
2600
 
 
2601
      gdk_window_set_background (frame->window, &color);
 
2602
    }
 
2603
  else
 
2604
    {
 
2605
      gtk_style_set_background (frame->style,
 
2606
                                frame->window, GTK_STATE_NORMAL);
 
2607
    }
 
2608
 }
 
2609
 
 
2610
static gboolean
 
2611
meta_frames_enter_notify_event      (GtkWidget           *widget,
 
2612
                                     GdkEventCrossing    *event)
 
2613
{
 
2614
  MetaUIFrame *frame;
 
2615
  MetaFrames *frames;
 
2616
  MetaFrameControl control;
 
2617
  
 
2618
  frames = META_FRAMES (widget);
 
2619
 
 
2620
  frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
 
2621
  if (frame == NULL)
 
2622
    return FALSE;
 
2623
 
 
2624
  control = get_control (frames, frame, event->x, event->y);
 
2625
  meta_frames_update_prelit_control (frames, frame, control);
 
2626
  
 
2627
  return TRUE;
 
2628
}
 
2629
 
 
2630
static gboolean
 
2631
meta_frames_leave_notify_event      (GtkWidget           *widget,
 
2632
                                     GdkEventCrossing    *event)
 
2633
{
 
2634
  MetaUIFrame *frame;
 
2635
  MetaFrames *frames;
 
2636
 
 
2637
  frames = META_FRAMES (widget);
 
2638
 
 
2639
  frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
 
2640
  if (frame == NULL)
 
2641
    return FALSE;
 
2642
 
 
2643
  meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE);
 
2644
  
 
2645
  clear_tip (frames);
 
2646
 
 
2647
  return TRUE;
 
2648
}
 
2649
 
 
2650
static GdkRectangle*
 
2651
control_rect (MetaFrameControl control,
 
2652
              MetaFrameGeometry *fgeom)
 
2653
{
 
2654
  GdkRectangle *rect;
 
2655
  
 
2656
  rect = NULL;
 
2657
  switch (control)
 
2658
    {
 
2659
    case META_FRAME_CONTROL_TITLE:
 
2660
      rect = &fgeom->title_rect;
 
2661
      break;
 
2662
    case META_FRAME_CONTROL_DELETE:
 
2663
      rect = &fgeom->close_rect.visible;
 
2664
      break;
 
2665
    case META_FRAME_CONTROL_MENU:
 
2666
      rect = &fgeom->menu_rect.visible;
 
2667
      break;
 
2668
    case META_FRAME_CONTROL_MINIMIZE:
 
2669
      rect = &fgeom->min_rect.visible;
 
2670
      break;
 
2671
    case META_FRAME_CONTROL_MAXIMIZE:
 
2672
    case META_FRAME_CONTROL_UNMAXIMIZE:
 
2673
      rect = &fgeom->max_rect.visible;
 
2674
      break;
 
2675
    case META_FRAME_CONTROL_SHADE:
 
2676
      rect = &fgeom->shade_rect.visible;
 
2677
      break;
 
2678
    case META_FRAME_CONTROL_UNSHADE:
 
2679
      rect = &fgeom->unshade_rect.visible;
 
2680
      break;
 
2681
    case META_FRAME_CONTROL_ABOVE:
 
2682
      rect = &fgeom->above_rect.visible;
 
2683
      break;
 
2684
    case META_FRAME_CONTROL_UNABOVE:
 
2685
      rect = &fgeom->unabove_rect.visible;
 
2686
      break;
 
2687
    case META_FRAME_CONTROL_STICK:
 
2688
      rect = &fgeom->stick_rect.visible;
 
2689
      break;
 
2690
    case META_FRAME_CONTROL_UNSTICK:
 
2691
      rect = &fgeom->unstick_rect.visible;
 
2692
      break;
 
2693
    case META_FRAME_CONTROL_RESIZE_SE:
 
2694
      break;
 
2695
    case META_FRAME_CONTROL_RESIZE_S:
 
2696
      break;
 
2697
    case META_FRAME_CONTROL_RESIZE_SW:
 
2698
      break;
 
2699
    case META_FRAME_CONTROL_RESIZE_N:
 
2700
      break;
 
2701
    case META_FRAME_CONTROL_RESIZE_NE:
 
2702
      break;
 
2703
    case META_FRAME_CONTROL_RESIZE_NW:
 
2704
      break;
 
2705
    case META_FRAME_CONTROL_RESIZE_W:
 
2706
      break;
 
2707
    case META_FRAME_CONTROL_RESIZE_E:
 
2708
      break;
 
2709
    case META_FRAME_CONTROL_NONE:
 
2710
      break;
 
2711
    case META_FRAME_CONTROL_CLIENT_AREA:
 
2712
      break;
 
2713
    }
 
2714
 
 
2715
  return rect;
 
2716
}
 
2717
 
 
2718
#define RESIZE_EXTENDS 15
 
2719
#define TOP_RESIZE_HEIGHT 2
 
2720
static MetaFrameControl
 
2721
get_control (MetaFrames *frames,
 
2722
             MetaUIFrame *frame,
 
2723
             int x, int y)
 
2724
{
 
2725
  MetaFrameGeometry fgeom;
 
2726
  MetaFrameFlags flags;
 
2727
  gboolean has_vert, has_horiz;
 
2728
  GdkRectangle client;
 
2729
  
 
2730
  meta_frames_calc_geometry (frames, frame, &fgeom);
 
2731
 
 
2732
  client.x = fgeom.left_width;
 
2733
  client.y = fgeom.top_height;
 
2734
  client.width = fgeom.width - fgeom.left_width - fgeom.right_width;
 
2735
  client.height = fgeom.height - fgeom.top_height - fgeom.bottom_height;  
 
2736
 
 
2737
  if (POINT_IN_RECT (x, y, client))
 
2738
    return META_FRAME_CONTROL_CLIENT_AREA;
 
2739
  
 
2740
  if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable))
 
2741
    return META_FRAME_CONTROL_DELETE;
 
2742
 
 
2743
  if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable))
 
2744
    return META_FRAME_CONTROL_MINIMIZE;
 
2745
 
 
2746
  if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable))
 
2747
    return META_FRAME_CONTROL_MENU;
 
2748
 
 
2749
  meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
 
2750
                 META_CORE_GET_FRAME_FLAGS, &flags,
 
2751
                 META_CORE_GET_END);
 
2752
  
 
2753
  has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
 
2754
  has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
 
2755
  
 
2756
  if (POINT_IN_RECT (x, y, fgeom.title_rect))
 
2757
    {
 
2758
      if (has_vert && y <= TOP_RESIZE_HEIGHT)
 
2759
        return META_FRAME_CONTROL_RESIZE_N;
 
2760
      else
 
2761
        return META_FRAME_CONTROL_TITLE;
 
2762
    }
 
2763
 
 
2764
  if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable))
 
2765
    {
 
2766
      if (flags & META_FRAME_MAXIMIZED)
 
2767
        return META_FRAME_CONTROL_UNMAXIMIZE;
 
2768
      else
 
2769
        return META_FRAME_CONTROL_MAXIMIZE;
 
2770
    }
 
2771
      
 
2772
  if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable))
 
2773
    {
 
2774
      return META_FRAME_CONTROL_SHADE;
 
2775
    }
 
2776
 
 
2777
  if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable))
 
2778
    {
 
2779
      return META_FRAME_CONTROL_UNSHADE;
 
2780
    }
 
2781
 
 
2782
  if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable))
 
2783
    {
 
2784
      return META_FRAME_CONTROL_ABOVE;
 
2785
    }
 
2786
 
 
2787
  if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable))
 
2788
    {
 
2789
      return META_FRAME_CONTROL_UNABOVE;
 
2790
    }
 
2791
 
 
2792
  if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable))
 
2793
    {
 
2794
      return META_FRAME_CONTROL_STICK;
 
2795
    }
 
2796
 
 
2797
  if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable))
 
2798
    {
 
2799
      return META_FRAME_CONTROL_UNSTICK;
 
2800
    }
 
2801
 
 
2802
  /* South resize always has priority over north resize,
 
2803
   * in case of overlap.
 
2804
   */
 
2805
 
 
2806
  if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
 
2807
      x >= (fgeom.width - fgeom.right_width - RESIZE_EXTENDS))
 
2808
    {
 
2809
      if (has_vert && has_horiz)
 
2810
        return META_FRAME_CONTROL_RESIZE_SE;
 
2811
      else if (has_vert)
 
2812
        return META_FRAME_CONTROL_RESIZE_S;
 
2813
      else if (has_horiz)
 
2814
        return META_FRAME_CONTROL_RESIZE_E;
 
2815
    }
 
2816
  else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
 
2817
           x <= (fgeom.left_width + RESIZE_EXTENDS))
 
2818
    {
 
2819
      if (has_vert && has_horiz)
 
2820
        return META_FRAME_CONTROL_RESIZE_SW;
 
2821
      else if (has_vert)
 
2822
        return META_FRAME_CONTROL_RESIZE_S;
 
2823
      else if (has_horiz)
 
2824
        return META_FRAME_CONTROL_RESIZE_W;
 
2825
    }
 
2826
  else if (y < (fgeom.top_height + RESIZE_EXTENDS) &&
 
2827
           x < RESIZE_EXTENDS)
 
2828
    {
 
2829
      if (has_vert && has_horiz)
 
2830
        return META_FRAME_CONTROL_RESIZE_NW;
 
2831
      else if (has_vert)
 
2832
        return META_FRAME_CONTROL_RESIZE_N;
 
2833
      else if (has_horiz)
 
2834
        return META_FRAME_CONTROL_RESIZE_W;
 
2835
    }
 
2836
  else if (y < (fgeom.top_height + RESIZE_EXTENDS) &&
 
2837
           x >= (fgeom.width - RESIZE_EXTENDS))
 
2838
    {
 
2839
      if (has_vert && has_horiz)
 
2840
        return META_FRAME_CONTROL_RESIZE_NE;
 
2841
      else if (has_vert)
 
2842
        return META_FRAME_CONTROL_RESIZE_N;
 
2843
      else if (has_horiz)
 
2844
        return META_FRAME_CONTROL_RESIZE_E;
 
2845
    }
 
2846
  else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS))
 
2847
    {
 
2848
      if (has_vert)
 
2849
        return META_FRAME_CONTROL_RESIZE_S;
 
2850
    }
 
2851
  else if (y <= TOP_RESIZE_HEIGHT)
 
2852
    {
 
2853
      if (has_vert)
 
2854
        return META_FRAME_CONTROL_RESIZE_N;
 
2855
      else if (has_horiz)
 
2856
        return META_FRAME_CONTROL_TITLE;
 
2857
    }
 
2858
  else if (x <= fgeom.left_width)
 
2859
    {
 
2860
      if (has_horiz)
 
2861
        return META_FRAME_CONTROL_RESIZE_W;
 
2862
    }
 
2863
  else if (x >= (fgeom.width - fgeom.right_width))
 
2864
    {
 
2865
      if (has_horiz)
 
2866
        return META_FRAME_CONTROL_RESIZE_E;
 
2867
    }
 
2868
 
 
2869
  if (y >= fgeom.top_height)
 
2870
    return META_FRAME_CONTROL_NONE;
 
2871
  else
 
2872
    return META_FRAME_CONTROL_TITLE;
 
2873
}
 
2874
 
 
2875
void
 
2876
meta_frames_push_delay_exposes (MetaFrames *frames)
 
2877
{
 
2878
  if (frames->expose_delay_count == 0)
 
2879
    {
 
2880
      /* Make sure we've repainted things */
 
2881
      gdk_window_process_all_updates ();
 
2882
      XFlush (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
 
2883
    }
 
2884
  
 
2885
  frames->expose_delay_count += 1;
 
2886
}
 
2887
 
 
2888
static void
 
2889
queue_pending_exposes_func (gpointer key, gpointer value, gpointer data)
 
2890
{
 
2891
  MetaUIFrame *frame;
 
2892
  MetaFrames *frames;
 
2893
 
 
2894
  frames = META_FRAMES (data);
 
2895
  frame = value;
 
2896
 
 
2897
  if (frame->expose_delayed)
 
2898
    {
 
2899
      invalidate_whole_window (frames, frame);
 
2900
      frame->expose_delayed = FALSE;
 
2901
    }
 
2902
}
 
2903
 
 
2904
void
 
2905
meta_frames_pop_delay_exposes  (MetaFrames *frames)
 
2906
{
 
2907
  g_return_if_fail (frames->expose_delay_count > 0);
 
2908
  
 
2909
  frames->expose_delay_count -= 1;
 
2910
 
 
2911
  if (frames->expose_delay_count == 0)
 
2912
    {
 
2913
      g_hash_table_foreach (frames->frames,
 
2914
                            queue_pending_exposes_func,
 
2915
                            frames);
 
2916
    }
 
2917
}
 
2918
 
 
2919
static void
 
2920
invalidate_whole_window (MetaFrames *frames,
 
2921
                         MetaUIFrame *frame)
 
2922
{
 
2923
  gdk_window_invalidate_rect (frame->window, NULL, FALSE);
 
2924
  invalidate_cache (frames, frame);
 
2925
}