~ubuntu-branches/ubuntu/trusty/gnome-panel/trusty-updates

« back to all changes in this revision

Viewing changes to .pc/git_fix_moving_applets.patch/gnome-panel/panel-toplevel.c

  • Committer: Package Import Robot
  • Author(s): Dmitry Shachnev
  • Date: 2014-02-24 09:50:50 UTC
  • Revision ID: package-import@ubuntu.com-20140224095050-4voujr65att1tq0o
Tags: 1:3.8.0-1ubuntu8
Backport upstream commit to fix moving applets in panel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 * panel-toplevel.c: The panel's toplevel window object.
 
4
 *
 
5
 * Copyright (C) 2003 Sun Microsystems, Inc.
 
6
 * Copyright (C) 2004 Rob Adams
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU General Public License as
 
10
 * published by the Free Software Foundation; either version 2 of the
 
11
 * License, or (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; if not, write to the Free Software
 
20
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
21
 * 02111-1307, USA.
 
22
 *
 
23
 * Authors:
 
24
 *      Mark McLoughlin <mark@skynet.ie>
 
25
 */
 
26
 
 
27
#include <config.h>
 
28
 
 
29
#include "panel-toplevel.h"
 
30
 
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
 
 
34
#include <gtk/gtk.h>
 
35
#include <gdk/gdkkeysyms.h>
 
36
#include <glib/gi18n.h>
 
37
 
 
38
#include <libpanel-util/panel-glib.h>
 
39
 
 
40
#include "panel-frame.h"
 
41
#include "panel-xutils.h"
 
42
#include "panel-multiscreen.h"
 
43
#include "panel-a11y.h"
 
44
#include "panel-typebuiltins.h"
 
45
#include "panel-marshal.h"
 
46
#include "panel-widget.h"
 
47
#include "panel-bindings.h"
 
48
#include "panel-struts.h"
 
49
#include "panel-lockdown.h"
 
50
#include "panel-schemas.h"
 
51
 
 
52
G_DEFINE_TYPE (PanelToplevel, panel_toplevel, GTK_TYPE_WINDOW)
 
53
 
 
54
#define PANEL_TOPLEVEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_TOPLEVEL, PanelToplevelPrivate))
 
55
 
 
56
#define DEFAULT_SIZE              48
 
57
#define DEFAULT_AUTO_HIDE_SIZE    1
 
58
#define DEFAULT_HIDE_DELAY        300
 
59
#define DEFAULT_UNHIDE_DELAY      100
 
60
#define DEFAULT_DND_THRESHOLD     8
 
61
#define MINIMUM_WIDTH             100
 
62
#define MAXIMUM_SIZE_SCREEN_RATIO 5
 
63
#define SNAP_TOLERANCE_FACTOR     6
 
64
#define DEFAULT_ARROW_SIZE        20
 
65
#define HANDLE_SIZE               10
 
66
 
 
67
typedef enum {
 
68
        PANEL_GRAB_OP_NONE,
 
69
        PANEL_GRAB_OP_MOVE,
 
70
        PANEL_GRAB_OP_RESIZE,
 
71
        PANEL_GRAB_OP_RESIZE_UP,
 
72
        PANEL_GRAB_OP_RESIZE_DOWN,
 
73
        PANEL_GRAB_OP_RESIZE_LEFT,
 
74
        PANEL_GRAB_OP_RESIZE_RIGHT
 
75
} PanelGrabOpType;
 
76
 
 
77
struct _PanelToplevelPrivate {
 
78
        char                   *toplevel_id;
 
79
 
 
80
        char                   *settings_path;
 
81
        GSettings              *settings;
 
82
        GSettings              *delayed_settings;
 
83
        guint                   apply_delayed_id;
 
84
 
 
85
        gboolean                expand;
 
86
        PanelOrientation        orientation;
 
87
        int                     size;
 
88
 
 
89
        /* relative to the monitor origin */
 
90
        int                     x;
 
91
        int                     y;
 
92
        /* relative to the bottom right corner, -1 to ignore and use x, y*/
 
93
        int                     x_right;
 
94
        int                     y_bottom;
 
95
 
 
96
        int                     monitor;
 
97
        /* this is used when the configured monitor is missing. We keep it so
 
98
         * we can move the toplevel to the right monitor when it becomes
 
99
         * available */
 
100
        int                     configured_monitor;
 
101
 
 
102
        int                     hide_delay;
 
103
        int                     unhide_delay;
 
104
        int                     auto_hide_size;
 
105
        PanelAnimationSpeed     animation_speed;
 
106
 
 
107
        int                     snap_tolerance;
 
108
        GtkSettings            *gtk_settings;
 
109
 
 
110
        PanelState              state;
 
111
 
 
112
        char                   *name;
 
113
        char                   *description;
 
114
 
 
115
        guint                   hide_timeout;
 
116
        guint                   unhide_timeout;
 
117
 
 
118
        GdkRectangle            geometry;
 
119
        PanelFrameEdge          edges;
 
120
 
 
121
        int                     original_width;
 
122
        int                     original_height;
 
123
 
 
124
        PanelGrabOpType         grab_op;
 
125
 
 
126
        /* The offset within the panel from which the panel
 
127
         * drag was initiated relative to the screen origin.
 
128
         */
 
129
        int                     drag_offset_x;
 
130
        int                     drag_offset_y;
 
131
 
 
132
        /* Saved state before for cancelled grab op */
 
133
        int                     orig_monitor;
 
134
        int                     orig_x;
 
135
        int                     orig_y;
 
136
        int                     orig_x_right;
 
137
        int                     orig_y_bottom;
 
138
        int                     orig_size;
 
139
        int                     orig_orientation;
 
140
 
 
141
        /* relative to the monitor origin */
 
142
        int                     animation_end_x;
 
143
        int                     animation_end_y;
 
144
        int                     animation_end_width;
 
145
        int                     animation_end_height;
 
146
        GTimeVal                animation_start_time;
 
147
        GTimeVal                animation_end_time;
 
148
        guint                   animation_timeout;
 
149
 
 
150
        PanelWidget            *panel_widget;
 
151
        PanelFrame             *inner_frame;
 
152
        GtkWidget              *table;
 
153
        GtkWidget              *hide_button_top;
 
154
        GtkWidget              *hide_button_bottom;
 
155
        GtkWidget              *hide_button_left;
 
156
        GtkWidget              *hide_button_right;
 
157
 
 
158
        gint                    n_autohide_disablers;
 
159
 
 
160
        guint                   auto_hide : 1;
 
161
        guint                   animate : 1;
 
162
        guint                   buttons_enabled : 1;
 
163
        guint                   arrows_enabled : 1;
 
164
 
 
165
        /* The co-ordinates are relative to center screen */
 
166
        guint                   x_centered : 1;
 
167
        guint                   y_centered : 1;
 
168
 
 
169
        /* The panel is not lined up with th screen edge */
 
170
        guint                   floating : 1;
 
171
 
 
172
        /* We are currently animating a hide/show */
 
173
        guint                   animating : 1;
 
174
 
 
175
        /* This is a keyboard initiated grab operation */
 
176
        guint                   grab_is_keyboard : 1;
 
177
 
 
178
        /* The x-y co-ordinates temporarily specify the panel center.
 
179
         * This is used when the panel is rotating, because the width/height
 
180
         * of the toplevel might change, so we need to compute new values for
 
181
         * those. */
 
182
        guint                   position_centered : 1;
 
183
 
 
184
        /* More saved grab op state */
 
185
        guint                   orig_x_centered : 1;
 
186
        guint                   orig_y_centered : 1;
 
187
 
 
188
        /* flag to see if we have already done geometry updating,
 
189
           if not then we're still loading and can ignore many things */
 
190
        guint                   updated_geometry_initial : 1;
 
191
        /* flag to see if we have done the initial animation */
 
192
        guint                   initial_animation_done : 1;
 
193
};
 
194
 
 
195
enum {
 
196
        HIDE_SIGNAL,
 
197
        UNHIDE_SIGNAL,
 
198
        POPUP_PANEL_MENU_SIGNAL,
 
199
        TOGGLE_EXPAND_SIGNAL,
 
200
        EXPAND_SIGNAL,
 
201
        UNEXPAND_SIGNAL,
 
202
        TOGGLE_HIDDEN_SIGNAL,
 
203
        BEGIN_MOVE_SIGNAL,
 
204
        BEGIN_RESIZE_SIGNAL,
 
205
        LAST_SIGNAL
 
206
};
 
207
 
 
208
enum {
 
209
        PROP_0,
 
210
        PROP_TOPLEVEL_ID,
 
211
        PROP_SETTINGS_PATH,
 
212
        PROP_NAME,
 
213
        PROP_EXPAND,
 
214
        PROP_ORIENTATION,
 
215
        PROP_SIZE,
 
216
        PROP_X,
 
217
        PROP_X_RIGHT,
 
218
        PROP_X_CENTERED,
 
219
        PROP_Y,
 
220
        PROP_Y_BOTTOM,
 
221
        PROP_Y_CENTERED,
 
222
        PROP_MONITOR,
 
223
        PROP_AUTOHIDE,
 
224
        PROP_HIDE_DELAY,
 
225
        PROP_UNHIDE_DELAY,
 
226
        PROP_AUTOHIDE_SIZE,
 
227
        PROP_ANIMATE,
 
228
        PROP_ANIMATION_SPEED,
 
229
        PROP_BUTTONS_ENABLED,
 
230
        PROP_ARROWS_ENABLED
 
231
};
 
232
 
 
233
static guint         toplevel_signals [LAST_SIGNAL] = { 0 };
 
234
static GSList       *toplevel_list = NULL;
 
235
 
 
236
static void panel_toplevel_calculate_animation_end_geometry (PanelToplevel *toplevel);
 
237
 
 
238
static gboolean panel_toplevel_position_is_writable (PanelToplevel *toplevel);
 
239
 
 
240
static void panel_toplevel_bind_gsettings       (PanelToplevel *toplevel);
 
241
static void panel_toplevel_set_toplevel_id      (PanelToplevel *toplevel,
 
242
                                                 const char    *toplevel_id);
 
243
static void panel_toplevel_set_settings_path    (PanelToplevel *toplevel,
 
244
                                                 const char    *settings_path);
 
245
static void panel_toplevel_set_animate          (PanelToplevel *toplevel,
 
246
                                                 gboolean       animate);
 
247
 
 
248
static void panel_toplevel_update_monitor       (PanelToplevel *toplevel);
 
249
static void panel_toplevel_set_monitor_internal (PanelToplevel *toplevel,
 
250
                                                 int            monitor,
 
251
                                                 gboolean       force_resize);
 
252
 
 
253
 
 
254
GSList *
 
255
panel_toplevel_list_toplevels (void)
 
256
{
 
257
        return toplevel_list;
 
258
}
 
259
 
 
260
PanelToplevel *
 
261
panel_toplevel_get_by_id (const char *toplevel_id)
 
262
{
 
263
        GSList *l;
 
264
 
 
265
        if (PANEL_GLIB_STR_EMPTY (toplevel_id))
 
266
                return NULL;
 
267
 
 
268
        for (l = toplevel_list; l; l = l->next) {
 
269
                PanelToplevel *toplevel = l->data;
 
270
 
 
271
                if (!g_strcmp0 (toplevel->priv->toplevel_id, toplevel_id))
 
272
                        return toplevel;
 
273
        }
 
274
 
 
275
        return NULL;
 
276
}
 
277
 
 
278
gboolean
 
279
panel_toplevel_is_last (PanelToplevel *toplevel)
 
280
{
 
281
        GSList *l;
 
282
 
 
283
        for (l = toplevel_list; l; l = l->next) {
 
284
                if (l->data != toplevel)
 
285
                        return FALSE;
 
286
        }
 
287
 
 
288
        return TRUE;
 
289
}
 
290
 
 
291
gboolean
 
292
panel_toplevel_find_empty_spot (GdkScreen        *screen,
 
293
                                PanelOrientation *orientation,
 
294
                                int              *monitor)
 
295
{
 
296
        int      *filled_spots;
 
297
        GSList   *li;
 
298
        int       i;
 
299
        gboolean  found_a_spot = FALSE;
 
300
 
 
301
        *monitor = 0;
 
302
        *orientation = PANEL_ORIENTATION_TOP;
 
303
 
 
304
        filled_spots = g_new0 (int, panel_multiscreen_monitors (screen));
 
305
 
 
306
        for (li = panel_toplevel_list_toplevels (); li != NULL; li = li->next) {
 
307
                PanelToplevel *toplevel = li->data;
 
308
                GdkScreen *toplevel_screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
309
                int toplevel_monitor = panel_toplevel_get_monitor (toplevel);
 
310
 
 
311
                if (toplevel_screen != screen ||
 
312
                    toplevel_monitor < 0)
 
313
                        continue;
 
314
 
 
315
                filled_spots[toplevel_monitor] |= panel_toplevel_get_orientation (toplevel);
 
316
        }
 
317
 
 
318
        for (i = 0; i < panel_multiscreen_monitors (screen); i++) {
 
319
                /* These are ordered based on "priority" of the
 
320
                   orientation when picking it */
 
321
                if ( ! (filled_spots[i] & PANEL_ORIENTATION_TOP)) {
 
322
                        *orientation = PANEL_ORIENTATION_TOP;
 
323
                        *monitor = i;
 
324
                        found_a_spot = TRUE;
 
325
                        break;
 
326
                } else if ( ! (filled_spots[i] & PANEL_ORIENTATION_BOTTOM)) {
 
327
                        *orientation = PANEL_ORIENTATION_BOTTOM;
 
328
                        *monitor = i;
 
329
                        found_a_spot = TRUE;
 
330
                        break;
 
331
                } else if ( ! (filled_spots[i] & PANEL_ORIENTATION_RIGHT)) {
 
332
                        *orientation = PANEL_ORIENTATION_RIGHT;
 
333
                        *monitor = i;
 
334
                        found_a_spot = TRUE;
 
335
                        break;
 
336
                } else if ( ! (filled_spots[i] & PANEL_ORIENTATION_LEFT)) {
 
337
                        *orientation = PANEL_ORIENTATION_LEFT;
 
338
                        *monitor = i;
 
339
                        found_a_spot = TRUE;
 
340
                        break;
 
341
                }
 
342
        }
 
343
 
 
344
        g_free (filled_spots);
 
345
 
 
346
        return found_a_spot;
 
347
}
 
348
 
 
349
static GdkScreen *
 
350
panel_toplevel_get_screen_geometry (PanelToplevel *toplevel,
 
351
                                    int           *width,
 
352
                                    int           *height)
 
353
{
 
354
        GdkScreen *screen;
 
355
 
 
356
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
 
357
        g_return_val_if_fail (width != NULL && height != NULL, NULL);
 
358
 
 
359
        screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
360
 
 
361
        *width  = gdk_screen_get_width (screen);
 
362
        *height = gdk_screen_get_height (screen);
 
363
 
 
364
        return screen;
 
365
}
 
366
 
 
367
static GdkScreen *
 
368
panel_toplevel_get_monitor_geometry (PanelToplevel *toplevel,
 
369
                                     int           *x,
 
370
                                     int           *y,
 
371
                                     int           *width,
 
372
                                     int           *height)
 
373
{
 
374
        GdkScreen *screen;
 
375
 
 
376
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
 
377
        g_return_val_if_fail (width != NULL && height != NULL, NULL);
 
378
 
 
379
        screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
380
 
 
381
        if (x) *x = panel_multiscreen_x (screen, toplevel->priv->monitor);
 
382
        if (y) *y = panel_multiscreen_y (screen, toplevel->priv->monitor);
 
383
 
 
384
        if (width)  *width  = panel_multiscreen_width  (screen, toplevel->priv->monitor);
 
385
        if (height) *height = panel_multiscreen_height (screen, toplevel->priv->monitor);
 
386
 
 
387
        return screen;
 
388
}
 
389
 
 
390
static GdkCursorType
 
391
panel_toplevel_grab_op_cursor (PanelToplevel   *toplevel,
 
392
                               PanelGrabOpType  grab_op)
 
393
{
 
394
        GdkCursorType retval = -1;
 
395
 
 
396
        switch (grab_op) {
 
397
        case PANEL_GRAB_OP_MOVE:
 
398
        case PANEL_GRAB_OP_RESIZE:
 
399
                if (toplevel->priv->grab_is_keyboard)
 
400
                        retval = GDK_CROSS;
 
401
                else
 
402
                        retval = GDK_FLEUR;
 
403
                break;
 
404
                break;
 
405
        case PANEL_GRAB_OP_RESIZE_UP:
 
406
                retval = GDK_TOP_SIDE;
 
407
                break;
 
408
        case PANEL_GRAB_OP_RESIZE_DOWN:
 
409
                retval = GDK_BOTTOM_SIDE;
 
410
                break;
 
411
        case PANEL_GRAB_OP_RESIZE_LEFT:
 
412
                retval = GDK_LEFT_SIDE;
 
413
                break;
 
414
        case PANEL_GRAB_OP_RESIZE_RIGHT:
 
415
                retval = GDK_RIGHT_SIDE;
 
416
                break;
 
417
        default:
 
418
                g_assert_not_reached ();
 
419
                break;
 
420
        }
 
421
 
 
422
        return retval;
 
423
}
 
424
 
 
425
static void
 
426
panel_toplevel_init_resize_drag_offsets (PanelToplevel   *toplevel,
 
427
                                         PanelGrabOpType  grab_op)
 
428
{
 
429
        toplevel->priv->drag_offset_x = 0;
 
430
        toplevel->priv->drag_offset_y = 0;
 
431
 
 
432
        switch (grab_op) {
 
433
        case PANEL_GRAB_OP_RESIZE_DOWN:
 
434
                toplevel->priv->drag_offset_y = toplevel->priv->geometry.y;
 
435
                break;
 
436
        case PANEL_GRAB_OP_RESIZE_UP:
 
437
                toplevel->priv->drag_offset_y =
 
438
                        toplevel->priv->geometry.y + toplevel->priv->geometry.height;
 
439
                break;
 
440
        case PANEL_GRAB_OP_RESIZE_RIGHT:
 
441
                toplevel->priv->drag_offset_x = toplevel->priv->geometry.x;
 
442
                break;
 
443
        case PANEL_GRAB_OP_RESIZE_LEFT:
 
444
                toplevel->priv->drag_offset_x =
 
445
                        toplevel->priv->geometry.x + toplevel->priv->geometry.width;
 
446
                break;
 
447
        default:
 
448
                g_assert_not_reached ();
 
449
                break;
 
450
        }
 
451
}
 
452
 
 
453
static void
 
454
panel_toplevel_warp_pointer (PanelToplevel *toplevel)
 
455
{
 
456
        GtkWidget    *widget;
 
457
        GdkRectangle  geometry;
 
458
        int           x, y;
 
459
 
 
460
        widget = GTK_WIDGET (toplevel);
 
461
 
 
462
        geometry = toplevel->priv->geometry;
 
463
 
 
464
        x = y = 0;
 
465
 
 
466
        switch (toplevel->priv->grab_op) {
 
467
        case PANEL_GRAB_OP_MOVE:
 
468
        case PANEL_GRAB_OP_RESIZE:
 
469
                x = (geometry.width  / 2);
 
470
                y = (geometry.height / 2);
 
471
                break;
 
472
        case PANEL_GRAB_OP_RESIZE_UP:
 
473
                x = (geometry.width  / 2);
 
474
                break;
 
475
        case PANEL_GRAB_OP_RESIZE_DOWN:
 
476
                x = (geometry.width  / 2);
 
477
                y = geometry.height;
 
478
                break;
 
479
        case PANEL_GRAB_OP_RESIZE_LEFT:
 
480
                y = (geometry.height / 2);
 
481
                break;
 
482
        case PANEL_GRAB_OP_RESIZE_RIGHT:
 
483
                x = geometry.width;
 
484
                y = (geometry.height / 2);
 
485
                break;
 
486
        default:
 
487
                g_assert_not_reached ();
 
488
                break;
 
489
        }
 
490
 
 
491
        if (toplevel->priv->grab_op == PANEL_GRAB_OP_MOVE ||
 
492
            toplevel->priv->grab_op == PANEL_GRAB_OP_RESIZE) {
 
493
                toplevel->priv->drag_offset_x = x;
 
494
                toplevel->priv->drag_offset_y = y;
 
495
        } else
 
496
                panel_toplevel_init_resize_drag_offsets (toplevel, toplevel->priv->grab_op);
 
497
 
 
498
        panel_warp_pointer (gtk_widget_get_window (widget), x, y);
 
499
}
 
500
 
 
501
static void
 
502
panel_toplevel_begin_grab_op (PanelToplevel   *toplevel,
 
503
                              PanelGrabOpType  op_type,
 
504
                              gboolean         grab_keyboard,
 
505
                              guint32          time_)
 
506
{
 
507
        GtkWidget     *widget;
 
508
        GdkWindow     *window;
 
509
        GdkCursorType  cursor_type;
 
510
        GdkCursor     *cursor;
 
511
        GdkDisplay    *display;
 
512
        GdkDevice     *pointer;
 
513
        GdkDevice     *keyboard;
 
514
        GdkDeviceManager *device_manager;
 
515
 
 
516
        if (toplevel->priv->state != PANEL_STATE_NORMAL ||
 
517
            toplevel->priv->grab_op != PANEL_GRAB_OP_NONE)
 
518
                return;
 
519
 
 
520
        if (panel_lockdown_get_panels_locked_down_s ())
 
521
                return;
 
522
 
 
523
        /* If any of the position/orientation are not writable,
 
524
           then we can't really move freely */
 
525
        if (op_type == PANEL_GRAB_OP_MOVE &&
 
526
            !panel_toplevel_position_is_writable (toplevel))
 
527
                return;
 
528
 
 
529
        /* If size is not writable, then we can't resize */
 
530
        if ((op_type == PANEL_GRAB_OP_RESIZE || 
 
531
             op_type == PANEL_GRAB_OP_RESIZE_UP || 
 
532
             op_type == PANEL_GRAB_OP_RESIZE_DOWN || 
 
533
             op_type == PANEL_GRAB_OP_RESIZE_LEFT || 
 
534
             op_type == PANEL_GRAB_OP_RESIZE_RIGHT) &&
 
535
            ! g_settings_is_writable (toplevel->priv->settings,
 
536
                                      PANEL_TOPLEVEL_SIZE_KEY))
 
537
                return;
 
538
 
 
539
        widget = GTK_WIDGET (toplevel);
 
540
        window = gtk_widget_get_window (widget);
 
541
 
 
542
        toplevel->priv->grab_op          = op_type;
 
543
        toplevel->priv->grab_is_keyboard = grab_keyboard;
 
544
 
 
545
        toplevel->priv->orig_monitor     = toplevel->priv->monitor;
 
546
        toplevel->priv->orig_x           = toplevel->priv->x;
 
547
        toplevel->priv->orig_x_right     = toplevel->priv->x_right;
 
548
        toplevel->priv->orig_x_centered  = toplevel->priv->x_centered;
 
549
        toplevel->priv->orig_y           = toplevel->priv->y;
 
550
        toplevel->priv->orig_y_bottom    = toplevel->priv->y_bottom;
 
551
        toplevel->priv->orig_y_centered  = toplevel->priv->y_centered;
 
552
        toplevel->priv->orig_size        = toplevel->priv->size;
 
553
        toplevel->priv->orig_orientation = toplevel->priv->orientation;
 
554
 
 
555
        gtk_grab_add (widget);
 
556
 
 
557
        if (toplevel->priv->grab_is_keyboard)
 
558
                panel_toplevel_warp_pointer (toplevel);
 
559
 
 
560
        cursor_type = panel_toplevel_grab_op_cursor (
 
561
                                toplevel, toplevel->priv->grab_op);
 
562
 
 
563
        cursor = gdk_cursor_new (cursor_type);
 
564
 
 
565
        display = gdk_window_get_display (window);
 
566
        device_manager = gdk_display_get_device_manager (display);
 
567
        pointer = gdk_device_manager_get_client_pointer (device_manager);
 
568
        keyboard = gdk_device_get_associated_device (pointer);
 
569
 
 
570
        gdk_device_grab (pointer, window,
 
571
                         GDK_OWNERSHIP_NONE, FALSE,
 
572
                         GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
 
573
                         cursor, time_);
 
574
 
 
575
        g_object_unref (cursor);
 
576
 
 
577
        if (grab_keyboard)
 
578
                gdk_device_grab (keyboard, window,
 
579
                                 GDK_OWNERSHIP_NONE, FALSE,
 
580
                                 GDK_KEY_PRESS | GDK_KEY_RELEASE,
 
581
                                 NULL, time_);
 
582
}
 
583
 
 
584
static void
 
585
panel_toplevel_end_grab_op (PanelToplevel *toplevel,
 
586
                            guint32        time_)
 
587
{
 
588
        GtkWidget *widget;
 
589
        GdkDisplay    *display;
 
590
        GdkDevice     *pointer;
 
591
        GdkDevice     *keyboard;
 
592
        GdkDeviceManager *device_manager;
 
593
 
 
594
        g_return_if_fail (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE);
 
595
 
 
596
        widget = GTK_WIDGET (toplevel);
 
597
 
 
598
        toplevel->priv->grab_op          = PANEL_GRAB_OP_NONE;
 
599
        toplevel->priv->grab_is_keyboard = FALSE;
 
600
 
 
601
        gtk_grab_remove (widget);
 
602
 
 
603
        display = gtk_widget_get_display (widget);
 
604
        device_manager = gdk_display_get_device_manager (display);
 
605
        pointer = gdk_device_manager_get_client_pointer (device_manager);
 
606
        keyboard = gdk_device_get_associated_device (pointer);
 
607
 
 
608
        gdk_device_ungrab (pointer, time_);
 
609
        gdk_device_ungrab (keyboard, time_);
 
610
}
 
611
 
 
612
static void
 
613
panel_toplevel_cancel_grab_op (PanelToplevel *toplevel,
 
614
                               guint32        time_)
 
615
{
 
616
        panel_toplevel_set_orientation (toplevel, toplevel->priv->orig_orientation);
 
617
        panel_toplevel_set_monitor (toplevel, toplevel->priv->orig_monitor);
 
618
        panel_toplevel_set_size (toplevel, toplevel->priv->orig_size);
 
619
        panel_toplevel_set_x (toplevel,
 
620
                              toplevel->priv->orig_x,
 
621
                              toplevel->priv->orig_x_right,
 
622
                              toplevel->priv->orig_x_centered);
 
623
        panel_toplevel_set_y (toplevel,
 
624
                              toplevel->priv->orig_y,
 
625
                              toplevel->priv->orig_y_bottom,
 
626
                              toplevel->priv->orig_y_centered);
 
627
}
 
628
 
 
629
static void
 
630
panel_toplevel_resize_to_pointer (PanelToplevel *toplevel,
 
631
                                  int            x,
 
632
                                  int            y)
 
633
{
 
634
        int new_size;
 
635
        int new_x, new_y;
 
636
        int new_x_right, new_y_bottom;
 
637
        int new_x_centered, new_y_centered;
 
638
        int monitor_width, monitor_height;
 
639
 
 
640
        new_size       = toplevel->priv->size;
 
641
        new_x          = toplevel->priv->x;
 
642
        new_y          = toplevel->priv->y;
 
643
        new_x_right    = toplevel->priv->x_right;
 
644
        new_y_bottom   = toplevel->priv->y_bottom;
 
645
        new_x_centered = toplevel->priv->x_centered;
 
646
        new_y_centered = toplevel->priv->y_centered;
 
647
 
 
648
        panel_toplevel_get_monitor_geometry (toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
649
 
 
650
        switch (toplevel->priv->grab_op) {
 
651
        case PANEL_GRAB_OP_RESIZE_UP:
 
652
                new_size = toplevel->priv->drag_offset_y - y;
 
653
                new_size = CLAMP (new_size, 0, monitor_height / 4);
 
654
                new_y -= (new_size - toplevel->priv->size);
 
655
                if (!toplevel->priv->y_centered && (new_y + new_size / 2) > monitor_height / 2)
 
656
                        new_y_bottom = monitor_height - (new_y + new_size);
 
657
                else
 
658
                        new_y_bottom = -1;
 
659
                break;
 
660
        case PANEL_GRAB_OP_RESIZE_DOWN:
 
661
                new_size = y - toplevel->priv->drag_offset_y;
 
662
                new_size = CLAMP (new_size, 0, monitor_height / 4);
 
663
                if (!toplevel->priv->y_centered && (new_y + new_size / 2) > monitor_height / 2)
 
664
                        new_y_bottom = monitor_height - (new_y + new_size);
 
665
                else
 
666
                        new_y_bottom = -1;
 
667
                break;
 
668
        case PANEL_GRAB_OP_RESIZE_LEFT:
 
669
                new_size = toplevel->priv->drag_offset_x - x;
 
670
                new_size = CLAMP (new_size, 0, monitor_width / 4);
 
671
                new_x -= (new_size - toplevel->priv->size);
 
672
                if (!toplevel->priv->x_centered && (new_x + new_size / 2) > monitor_width / 2)
 
673
                        new_x_right = monitor_width - (new_x + new_size);
 
674
                else
 
675
                        new_x_right = -1;
 
676
                break;
 
677
        case PANEL_GRAB_OP_RESIZE_RIGHT:
 
678
                new_size = x - toplevel->priv->drag_offset_x;
 
679
                new_size = CLAMP (new_size, 0, monitor_width / 4);
 
680
                if (!toplevel->priv->x_centered && (new_x + new_size / 2) > monitor_width / 2)
 
681
                        new_x_right = monitor_width - (new_x + new_size);
 
682
                else
 
683
                        new_x_right = -1;
 
684
                break;
 
685
        default:
 
686
                g_assert_not_reached ();
 
687
                break;
 
688
        }
 
689
 
 
690
        if (new_size == 0)
 
691
                return;
 
692
 
 
693
        panel_toplevel_set_x (toplevel, new_x, new_x_right, new_x_centered);
 
694
        panel_toplevel_set_y (toplevel, new_y, new_y_bottom, new_y_centered);
 
695
        panel_toplevel_set_size (toplevel, new_size);
 
696
}
 
697
 
 
698
/* this is called for expanded panels that are dragged around */
 
699
static void
 
700
panel_toplevel_calc_new_orientation (PanelToplevel *toplevel,
 
701
                                     int            pointer_x,
 
702
                                     int            pointer_y)
 
703
{
 
704
        PanelOrientation  new_orientation;
 
705
        GdkScreen        *screen;
 
706
        int               hborder, vborder;
 
707
        int               monitor;
 
708
        int               monitor_width, monitor_height;
 
709
        int               new_x, new_y;
 
710
 
 
711
        screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
712
 
 
713
        monitor = panel_multiscreen_get_monitor_at_point (screen, pointer_x, pointer_y);
 
714
 
 
715
        if (toplevel->priv->geometry.height < toplevel->priv->geometry.width)
 
716
                vborder = hborder = (3 * toplevel->priv->geometry.height) >> 1;
 
717
        else
 
718
                vborder = hborder = (3 * toplevel->priv->geometry.width)  >> 1;
 
719
 
 
720
        new_x = pointer_x - panel_multiscreen_x (screen, monitor);
 
721
        new_y = pointer_y - panel_multiscreen_y (screen, monitor);
 
722
        monitor_width = panel_multiscreen_width (screen, monitor);
 
723
        monitor_height = panel_multiscreen_height (screen, monitor);
 
724
 
 
725
        new_orientation = toplevel->priv->orientation;
 
726
 
 
727
        switch (toplevel->priv->orientation) {
 
728
        case PANEL_ORIENTATION_TOP:
 
729
                if (new_y > (monitor_height - hborder))
 
730
                        new_orientation = PANEL_ORIENTATION_BOTTOM;
 
731
 
 
732
                else if (new_y > hborder) {
 
733
                        if (new_x > (monitor_width - vborder))
 
734
                                new_orientation = PANEL_ORIENTATION_RIGHT;
 
735
                        else if (new_x < vborder)
 
736
                                new_orientation = PANEL_ORIENTATION_LEFT;
 
737
                } 
 
738
                break;
 
739
        case PANEL_ORIENTATION_BOTTOM:
 
740
                if (new_y < hborder)
 
741
                        new_orientation = PANEL_ORIENTATION_TOP;
 
742
 
 
743
                else if (new_y < (monitor_height - hborder)) {
 
744
                        if (new_x > (monitor_width - vborder))
 
745
                                new_orientation = PANEL_ORIENTATION_RIGHT;
 
746
                        else if (new_x < vborder)
 
747
                                new_orientation = PANEL_ORIENTATION_LEFT;
 
748
                } 
 
749
                break;
 
750
        case PANEL_ORIENTATION_LEFT:
 
751
                if (new_x > (monitor_width - vborder))
 
752
                        new_orientation = PANEL_ORIENTATION_RIGHT;
 
753
 
 
754
                else if (new_x > vborder) {
 
755
                        if (new_y > (monitor_height - hborder))
 
756
                                new_orientation = PANEL_ORIENTATION_BOTTOM;
 
757
                        else if (new_y < hborder)
 
758
                                new_orientation = PANEL_ORIENTATION_TOP;
 
759
                } 
 
760
                break;
 
761
        case PANEL_ORIENTATION_RIGHT:
 
762
                if (new_x < vborder)
 
763
                        new_orientation = PANEL_ORIENTATION_LEFT;
 
764
 
 
765
                else if (new_x < (monitor_width - vborder)) {
 
766
                        if (new_y > (monitor_height - hborder))
 
767
                                new_orientation = PANEL_ORIENTATION_BOTTOM;
 
768
                        else if (new_y < hborder)
 
769
                                new_orientation = PANEL_ORIENTATION_TOP;
 
770
                }
 
771
                break;
 
772
        default:
 
773
                g_assert_not_reached ();
 
774
                break;
 
775
        }
 
776
 
 
777
        panel_toplevel_set_monitor (toplevel, monitor);
 
778
        panel_toplevel_set_orientation (toplevel, new_orientation);
 
779
}
 
780
 
 
781
static void
 
782
panel_toplevel_move_to (PanelToplevel *toplevel,
 
783
                        int            new_x,
 
784
                        int            new_y)
 
785
{
 
786
        GdkScreen        *screen;
 
787
        PanelOrientation  new_orientation;
 
788
        gboolean          x_centered, y_centered;
 
789
        int               screen_width, screen_height;
 
790
        int               monitor_width, monitor_height;
 
791
        int               width, height;
 
792
        int               new_monitor;
 
793
        int               x, y, x_right, y_bottom;
 
794
        int               snap_tolerance;
 
795
 
 
796
        screen = panel_toplevel_get_screen_geometry (
 
797
                        toplevel, &screen_width, &screen_height);
 
798
 
 
799
        width  = toplevel->priv->geometry.width;
 
800
        height = toplevel->priv->geometry.height;
 
801
 
 
802
        snap_tolerance = toplevel->priv->snap_tolerance;
 
803
 
 
804
        new_x = CLAMP (new_x, 0, screen_width  - width);
 
805
        new_y = CLAMP (new_y, 0, screen_height - height);
 
806
 
 
807
        new_orientation = toplevel->priv->orientation;
 
808
 
 
809
        if (new_x <= snap_tolerance &&
 
810
            toplevel->priv->orientation & PANEL_VERTICAL_MASK)
 
811
                new_orientation = PANEL_ORIENTATION_LEFT;
 
812
 
 
813
        else if ((new_x + width) >= (screen_width - snap_tolerance) &&
 
814
                 toplevel->priv->orientation & PANEL_VERTICAL_MASK)
 
815
                new_orientation = PANEL_ORIENTATION_RIGHT;
 
816
 
 
817
        if (new_y <= snap_tolerance &&
 
818
            toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)
 
819
                new_orientation = PANEL_ORIENTATION_TOP;
 
820
 
 
821
        else if ((new_y + height) >= (screen_height - snap_tolerance) &&
 
822
                 toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)
 
823
                new_orientation = PANEL_ORIENTATION_BOTTOM;
 
824
 
 
825
        new_monitor = panel_multiscreen_get_monitor_at_point (screen, new_x, new_y);
 
826
 
 
827
        panel_toplevel_get_monitor_geometry (
 
828
                        toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
829
 
 
830
        x_centered = toplevel->priv->x_centered;
 
831
        y_centered = toplevel->priv->y_centered;
 
832
 
 
833
        x = new_x - panel_multiscreen_x (screen, new_monitor);
 
834
        y = new_y - panel_multiscreen_y (screen, new_monitor);
 
835
 
 
836
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 
837
                y_centered = FALSE;
 
838
                if (new_y <= snap_tolerance ||
 
839
                    new_y + height >= screen_height - snap_tolerance)
 
840
                        x_centered = abs (x - ((monitor_width - width) / 2))
 
841
                                                                <= snap_tolerance;
 
842
                else
 
843
                        x_centered = FALSE;
 
844
        } else {
 
845
                x_centered = FALSE;
 
846
                if (new_x <= snap_tolerance ||
 
847
                    new_x + width >= screen_width - snap_tolerance)
 
848
                        y_centered = abs (y - ((monitor_height - height) / 2))
 
849
                                                                <= snap_tolerance;
 
850
                else
 
851
                        y_centered = FALSE;
 
852
        }
 
853
 
 
854
        if (x_centered)
 
855
                x = (monitor_width  - width) / 2;
 
856
        if (y_centered)
 
857
                y = (monitor_height - height) / 2;
 
858
 
 
859
        if (!x_centered && (x + width / 2) > monitor_width / 2)
 
860
                x_right = monitor_width - (x + width);
 
861
        else
 
862
                x_right = -1;
 
863
 
 
864
        if (!y_centered && (y + height / 2) > monitor_height / 2)
 
865
                y_bottom = monitor_height - (y + height);
 
866
        else
 
867
                y_bottom = -1;
 
868
 
 
869
        panel_toplevel_set_monitor (toplevel, new_monitor);
 
870
        panel_toplevel_set_orientation (toplevel, new_orientation);
 
871
        panel_toplevel_set_x (toplevel, x, x_right, x_centered);
 
872
        panel_toplevel_set_y (toplevel, y, y_bottom, y_centered);
 
873
}
 
874
 
 
875
static void
 
876
panel_toplevel_move_to_pointer (PanelToplevel *toplevel,
 
877
                                int            pointer_x,
 
878
                                int            pointer_y)
 
879
{
 
880
        int new_x, new_y;
 
881
 
 
882
        new_x = pointer_x - toplevel->priv->drag_offset_x;
 
883
        new_y = pointer_y - toplevel->priv->drag_offset_y;
 
884
 
 
885
        panel_toplevel_move_to (toplevel, new_x, new_y);
 
886
}
 
887
 
 
888
static void
 
889
panel_toplevel_rotate_to_pointer (PanelToplevel *toplevel,
 
890
                                  int            pointer_x,
 
891
                                  int            pointer_y)
 
892
{
 
893
        int        x_diff, y_diff;
 
894
        int        x, y;
 
895
        int        snap_tolerance;
 
896
 
 
897
        x = toplevel->priv->geometry.x;
 
898
        y = toplevel->priv->geometry.y;
 
899
        snap_tolerance = toplevel->priv->snap_tolerance;
 
900
 
 
901
        x_diff = pointer_x - (x + toplevel->priv->geometry.width / 2);
 
902
        y_diff = pointer_y - (y + toplevel->priv->geometry.height / 2);
 
903
 
 
904
        if (((-y_diff > x_diff + snap_tolerance) && x_diff > 0 && y_diff < 0) ||
 
905
            (( y_diff < x_diff + snap_tolerance) && x_diff < 0 && y_diff < 0))
 
906
                panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_RIGHT);
 
907
 
 
908
        else if (((-x_diff < y_diff - snap_tolerance) && x_diff > 0 && y_diff < 0) ||
 
909
                 (( x_diff > y_diff - snap_tolerance) && x_diff > 0 && y_diff > 0))
 
910
                panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_BOTTOM);
 
911
 
 
912
        else if ((( y_diff > x_diff + snap_tolerance) && x_diff > 0 && y_diff > 0) ||
 
913
                 ((-y_diff < x_diff + snap_tolerance) && x_diff < 0 && y_diff > 0))
 
914
                panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_LEFT);
 
915
 
 
916
        else if (((-x_diff > y_diff - snap_tolerance) && x_diff < 0 && y_diff > 0) ||
 
917
                 (( x_diff < y_diff - snap_tolerance) && x_diff < 0 && y_diff < 0))
 
918
                panel_toplevel_set_orientation (toplevel, PANEL_ORIENTATION_TOP);
 
919
}
 
920
 
 
921
static gboolean
 
922
panel_toplevel_warp_pointer_increment (PanelToplevel *toplevel,
 
923
                                       int            keyval,
 
924
                                       int            increment)
 
925
{
 
926
        GdkScreen       *screen;
 
927
        GdkWindow       *root_window;
 
928
        GdkModifierType  modifier_mask;
 
929
        int              new_x, new_y;
 
930
 
 
931
        screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
932
        root_window = gdk_screen_get_root_window (screen);
 
933
 
 
934
        gdk_window_get_device_position(root_window, gtk_get_current_event_device (), &new_x, &new_y, &modifier_mask);
 
935
 
 
936
        switch (keyval) {
 
937
        case GDK_KEY_Up:
 
938
        case GDK_KEY_KP_Up:
 
939
                new_y -= increment;
 
940
                break;
 
941
        case GDK_KEY_Left:
 
942
        case GDK_KEY_KP_Left:
 
943
                new_x -= increment;
 
944
                break;
 
945
        case GDK_KEY_Down:
 
946
        case GDK_KEY_KP_Down:
 
947
                new_y += increment;
 
948
                break;
 
949
        case GDK_KEY_Right:
 
950
        case GDK_KEY_KP_Right:
 
951
                new_x += increment;
 
952
                break;
 
953
        default:
 
954
                g_assert_not_reached ();
 
955
                return FALSE;
 
956
        }
 
957
 
 
958
        panel_warp_pointer (root_window, new_x, new_y);
 
959
 
 
960
        return TRUE;
 
961
}
 
962
 
 
963
static gboolean
 
964
panel_toplevel_move_keyboard_floating (PanelToplevel *toplevel,
 
965
                                       GdkEventKey   *event)
 
966
{
 
967
#define SMALL_INCREMENT  1
 
968
#define NORMAL_INCREMENT 10
 
969
 
 
970
        int increment = NORMAL_INCREMENT;
 
971
 
 
972
        if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_SHIFT_MASK)
 
973
                increment = SMALL_INCREMENT;
 
974
 
 
975
        return panel_toplevel_warp_pointer_increment (
 
976
                                toplevel, event->keyval, increment);
 
977
 
 
978
#undef SMALL_INCREMENT
 
979
#undef NORMAL_INCREMENT
 
980
}
 
981
 
 
982
static gboolean
 
983
panel_toplevel_move_keyboard_expanded (PanelToplevel *toplevel,
 
984
                                       GdkEventKey   *event)
 
985
{
 
986
        PanelOrientation new_orientation;
 
987
 
 
988
        switch (event->keyval) {
 
989
        case GDK_KEY_Up:
 
990
        case GDK_KEY_KP_Up:
 
991
                new_orientation = PANEL_ORIENTATION_TOP;
 
992
                break;
 
993
        case GDK_KEY_Left:
 
994
        case GDK_KEY_KP_Left:
 
995
                new_orientation = PANEL_ORIENTATION_LEFT;
 
996
                break;
 
997
        case GDK_KEY_Down:
 
998
        case GDK_KEY_KP_Down:
 
999
                new_orientation = PANEL_ORIENTATION_BOTTOM;
 
1000
                break;
 
1001
        case GDK_KEY_Right:
 
1002
        case GDK_KEY_KP_Right:
 
1003
                new_orientation = PANEL_ORIENTATION_RIGHT;
 
1004
                break;
 
1005
        default:
 
1006
                g_assert_not_reached ();
 
1007
                return FALSE;
 
1008
        }
 
1009
 
 
1010
        panel_toplevel_set_orientation (toplevel, new_orientation);
 
1011
 
 
1012
        return TRUE;
 
1013
}
 
1014
 
 
1015
static gboolean
 
1016
panel_toplevel_initial_resize_keypress (PanelToplevel *toplevel,
 
1017
                                        GdkEventKey   *event)
 
1018
{
 
1019
        PanelGrabOpType grab_op;
 
1020
 
 
1021
        switch (event->keyval) {
 
1022
        case GDK_KEY_Up:
 
1023
        case GDK_KEY_KP_Up:
 
1024
                if (!(toplevel->priv->orientation & PANEL_HORIZONTAL_MASK))
 
1025
                        return FALSE;
 
1026
                grab_op = PANEL_GRAB_OP_RESIZE_UP;
 
1027
                break;
 
1028
        case GDK_KEY_Left:
 
1029
        case GDK_KEY_KP_Left:
 
1030
                if (!(toplevel->priv->orientation & PANEL_VERTICAL_MASK))
 
1031
                        return FALSE;
 
1032
                grab_op = PANEL_GRAB_OP_RESIZE_LEFT;
 
1033
                break;
 
1034
        case GDK_KEY_Down:
 
1035
        case GDK_KEY_KP_Down:
 
1036
                if (!(toplevel->priv->orientation & PANEL_HORIZONTAL_MASK))
 
1037
                        return FALSE;
 
1038
                grab_op = PANEL_GRAB_OP_RESIZE_DOWN;
 
1039
                break;
 
1040
        case GDK_KEY_Right:
 
1041
        case GDK_KEY_KP_Right:
 
1042
                if (!(toplevel->priv->orientation & PANEL_VERTICAL_MASK))
 
1043
                        return FALSE;
 
1044
                grab_op = PANEL_GRAB_OP_RESIZE_RIGHT;
 
1045
                break;
 
1046
        default:
 
1047
                g_assert_not_reached ();
 
1048
                return FALSE;
 
1049
        }
 
1050
 
 
1051
        panel_toplevel_end_grab_op (toplevel, event->time);
 
1052
        panel_toplevel_begin_grab_op (toplevel, grab_op, TRUE, event->time);
 
1053
 
 
1054
        return TRUE;
 
1055
}
 
1056
 
 
1057
static gboolean
 
1058
panel_toplevel_handle_grab_op_key_event (PanelToplevel *toplevel,
 
1059
                                         GdkEventKey   *event)
 
1060
{
 
1061
        gboolean retval = FALSE;
 
1062
 
 
1063
        switch (event->keyval) {
 
1064
        case GDK_KEY_Up:
 
1065
        case GDK_KEY_KP_Up:
 
1066
        case GDK_KEY_Left:
 
1067
        case GDK_KEY_KP_Left:
 
1068
        case GDK_KEY_Down:
 
1069
        case GDK_KEY_KP_Down:
 
1070
        case GDK_KEY_Right:
 
1071
        case GDK_KEY_KP_Right:
 
1072
                switch (toplevel->priv->grab_op) {
 
1073
                case PANEL_GRAB_OP_MOVE:
 
1074
                        if (toplevel->priv->expand)
 
1075
                                retval = panel_toplevel_move_keyboard_expanded (
 
1076
                                                                        toplevel, event);
 
1077
                        else
 
1078
                                retval = panel_toplevel_move_keyboard_floating (
 
1079
                                                                        toplevel, event);
 
1080
                        break;
 
1081
                case PANEL_GRAB_OP_RESIZE:
 
1082
                        retval = panel_toplevel_initial_resize_keypress (toplevel, event);
 
1083
                        break;
 
1084
                case PANEL_GRAB_OP_RESIZE_UP:
 
1085
                case PANEL_GRAB_OP_RESIZE_DOWN:
 
1086
                case PANEL_GRAB_OP_RESIZE_LEFT:
 
1087
                case PANEL_GRAB_OP_RESIZE_RIGHT:
 
1088
                        retval = panel_toplevel_warp_pointer_increment (
 
1089
                                                toplevel, event->keyval, 1);
 
1090
                        break;
 
1091
                default:
 
1092
                        g_assert_not_reached ();
 
1093
                        break;
 
1094
                }
 
1095
                break;
 
1096
        case GDK_KEY_Escape:
 
1097
                panel_toplevel_cancel_grab_op (toplevel, event->time);
 
1098
        case GDK_KEY_Return: /* drop through*/
 
1099
        case GDK_KEY_KP_Enter:
 
1100
        case GDK_KEY_space:
 
1101
        case GDK_KEY_KP_Space:
 
1102
                panel_toplevel_end_grab_op (toplevel, event->time);
 
1103
                retval = TRUE;
 
1104
        default: /* drop through*/
 
1105
                break;
 
1106
        }
 
1107
 
 
1108
        return retval;
 
1109
}
 
1110
 
 
1111
static gboolean
 
1112
panel_toplevel_handle_grab_op_motion_event (PanelToplevel  *toplevel,
 
1113
                                            GdkEventMotion *event)
 
1114
{
 
1115
        switch (toplevel->priv->grab_op) {
 
1116
        case PANEL_GRAB_OP_MOVE:
 
1117
                if (toplevel->priv->expand)
 
1118
                        panel_toplevel_calc_new_orientation (
 
1119
                                        toplevel, event->x_root, event->y_root);
 
1120
 
 
1121
                else if ((event->state & gtk_accelerator_get_default_mod_mask ()) == GDK_CONTROL_MASK)
 
1122
                        panel_toplevel_rotate_to_pointer (
 
1123
                                        toplevel, event->x_root, event->y_root);
 
1124
 
 
1125
                else
 
1126
                        panel_toplevel_move_to_pointer (
 
1127
                                        toplevel, event->x_root, event->y_root);
 
1128
                return TRUE;
 
1129
        case PANEL_GRAB_OP_RESIZE_UP:
 
1130
        case PANEL_GRAB_OP_RESIZE_DOWN:
 
1131
        case PANEL_GRAB_OP_RESIZE_LEFT:
 
1132
        case PANEL_GRAB_OP_RESIZE_RIGHT:
 
1133
                panel_toplevel_resize_to_pointer (toplevel, event->x_root, event->y_root);
 
1134
                return TRUE;
 
1135
        default:
 
1136
                break;
 
1137
        }
 
1138
 
 
1139
        return FALSE;
 
1140
}
 
1141
 
 
1142
static void
 
1143
panel_toplevel_calc_floating (PanelToplevel *toplevel)
 
1144
{
 
1145
        int        screen_width, screen_height;
 
1146
        int        monitor_x, monitor_y;
 
1147
        int        monitor_width, monitor_height;
 
1148
        int        x, y;
 
1149
        int        snap_tolerance;
 
1150
 
 
1151
        if (toplevel->priv->expand) {
 
1152
                toplevel->priv->floating = FALSE;
 
1153
                return;
 
1154
        }
 
1155
 
 
1156
        panel_toplevel_get_screen_geometry (toplevel,
 
1157
                                            &screen_width, &screen_height);
 
1158
        panel_toplevel_get_monitor_geometry (toplevel, &monitor_x, &monitor_y,
 
1159
                                             &monitor_width, &monitor_height);
 
1160
 
 
1161
        if (toplevel->priv->x_right == -1)
 
1162
                x = monitor_x + toplevel->priv->x;
 
1163
        else
 
1164
                x = monitor_x + (monitor_width - (toplevel->priv->x_right + toplevel->priv->geometry.width));
 
1165
        if (toplevel->priv->y_bottom == -1)
 
1166
                y = monitor_y + toplevel->priv->y;
 
1167
        else
 
1168
                y = monitor_y + (monitor_height - (toplevel->priv->y_bottom + toplevel->priv->geometry.height));
 
1169
 
 
1170
        snap_tolerance = toplevel->priv->snap_tolerance;
 
1171
 
 
1172
        //FIXME? everywhere else, snap_tolerance is relative to the monitor,
 
1173
        //not the screen
 
1174
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)
 
1175
                toplevel->priv->floating =
 
1176
                        (y > snap_tolerance) && (y < (screen_height - toplevel->priv->geometry.height - snap_tolerance));
 
1177
        else
 
1178
                toplevel->priv->floating =
 
1179
                        (x > snap_tolerance) && (x < (screen_width - toplevel->priv->geometry.width - snap_tolerance));
 
1180
}
 
1181
 
 
1182
void 
 
1183
panel_toplevel_push_autohide_disabler (PanelToplevel *toplevel)
 
1184
{
 
1185
        g_return_if_fail (toplevel != NULL);
 
1186
 
 
1187
        if (!toplevel->priv->n_autohide_disablers++)
 
1188
                panel_toplevel_queue_auto_hide (toplevel);
 
1189
}
 
1190
 
 
1191
void
 
1192
panel_toplevel_pop_autohide_disabler (PanelToplevel *toplevel)
 
1193
{
 
1194
        g_return_if_fail (toplevel != NULL);
 
1195
        g_return_if_fail (toplevel->priv->n_autohide_disablers > 0);
 
1196
 
 
1197
        if (!--toplevel->priv->n_autohide_disablers)
 
1198
                panel_toplevel_queue_auto_hide (toplevel);
 
1199
}
 
1200
 
 
1201
static gboolean
 
1202
panel_toplevel_get_autohide_disabled (PanelToplevel *toplevel)
 
1203
{
 
1204
        return toplevel->priv->n_autohide_disablers > 0 ? TRUE : FALSE;
 
1205
}
 
1206
 
 
1207
static gboolean
 
1208
panel_toplevel_hide_button_event (PanelToplevel  *toplevel,
 
1209
                                  GdkEventButton *event,
 
1210
                                  GtkButton      *button)
 
1211
{
 
1212
        if (event->button == 1)
 
1213
                return FALSE;
 
1214
 
 
1215
        return gtk_widget_event (GTK_WIDGET (toplevel), (GdkEvent *) event);
 
1216
}
 
1217
 
 
1218
static void
 
1219
panel_toplevel_hide_button_clicked (PanelToplevel *toplevel,
 
1220
                                    GtkButton     *button)
 
1221
{
 
1222
        GtkArrowType arrow_type;
 
1223
        gboolean ltr;
 
1224
 
 
1225
        if (toplevel->priv->animating ||
 
1226
            toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN)
 
1227
                return;
 
1228
 
 
1229
        ltr = gtk_widget_get_direction (GTK_WIDGET (toplevel)) == GTK_TEXT_DIR_LTR;
 
1230
        arrow_type = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "arrow-type"));
 
1231
 
 
1232
        if (toplevel->priv->state == PANEL_STATE_NORMAL) {
 
1233
                GtkDirectionType direction = -1;
 
1234
 
 
1235
                switch (arrow_type) {
 
1236
                case GTK_ARROW_UP:
 
1237
                        direction = GTK_DIR_UP;
 
1238
                        break;
 
1239
                case GTK_ARROW_DOWN:
 
1240
                        direction = GTK_DIR_DOWN;
 
1241
                        break;
 
1242
                case GTK_ARROW_LEFT:
 
1243
                        direction = ltr ? GTK_DIR_LEFT : GTK_DIR_RIGHT;
 
1244
                        break;
 
1245
                case GTK_ARROW_RIGHT:
 
1246
                        direction = ltr ? GTK_DIR_RIGHT : GTK_DIR_LEFT;
 
1247
                        break;
 
1248
                default:
 
1249
                        g_assert_not_reached ();
 
1250
                        break;
 
1251
                }
 
1252
 
 
1253
                panel_toplevel_hide (toplevel, FALSE, direction);
 
1254
        } else
 
1255
                panel_toplevel_unhide (toplevel);
 
1256
}
 
1257
 
 
1258
static GtkWidget *
 
1259
panel_toplevel_add_hide_button (PanelToplevel *toplevel,
 
1260
                                GtkArrowType   arrow_type,
 
1261
                                int            left_attach,
 
1262
                                int            right_attach,
 
1263
                                int            top_attach,
 
1264
                                int            bottom_attach)
 
1265
{
 
1266
        GtkWidget *button;
 
1267
        AtkObject *obj;
 
1268
        GtkWidget *arrow;
 
1269
        int        arrow_size;
 
1270
        
 
1271
        button = gtk_button_new ();
 
1272
        obj = gtk_widget_get_accessible (button);
 
1273
        atk_object_set_name (obj, _("Hide Panel"));
 
1274
        gtk_widget_set_can_default (button, FALSE);
 
1275
 
 
1276
        gtk_widget_style_get (GTK_WIDGET (toplevel),
 
1277
                              "arrow-size", &arrow_size,
 
1278
                              NULL);
 
1279
 
 
1280
        switch (arrow_type) {
 
1281
        case GTK_ARROW_UP:
 
1282
                gtk_widget_set_size_request (button, -1, arrow_size);
 
1283
                break;
 
1284
        case GTK_ARROW_DOWN:
 
1285
                gtk_widget_set_size_request (button, -1, arrow_size);
 
1286
                break;
 
1287
        case GTK_ARROW_LEFT:
 
1288
                gtk_widget_set_size_request (button, arrow_size, -1);
 
1289
                break;
 
1290
        case GTK_ARROW_RIGHT:
 
1291
                gtk_widget_set_size_request (button, arrow_size, -1);
 
1292
                break;
 
1293
        default:
 
1294
                g_assert_not_reached ();
 
1295
                break;
 
1296
        }
 
1297
 
 
1298
        arrow = gtk_arrow_new (arrow_type, GTK_SHADOW_NONE);
 
1299
        gtk_misc_set_padding (GTK_MISC (arrow), 0, 0);
 
1300
        gtk_container_add (GTK_CONTAINER (button), arrow);
 
1301
        gtk_widget_show (arrow);
 
1302
 
 
1303
        g_object_set_data (G_OBJECT (button),
 
1304
                           "arrow-type",
 
1305
                           GINT_TO_POINTER (arrow_type));
 
1306
 
 
1307
        g_signal_connect_swapped (button, "clicked",
 
1308
                                  G_CALLBACK (panel_toplevel_hide_button_clicked), toplevel);
 
1309
        g_signal_connect_swapped (button, "button_press_event",
 
1310
                                  G_CALLBACK (panel_toplevel_hide_button_event), toplevel);
 
1311
        g_signal_connect_swapped (button, "button_release_event",
 
1312
                                  G_CALLBACK (panel_toplevel_hide_button_event), toplevel);
 
1313
                                  
 
1314
        gtk_table_attach (GTK_TABLE (toplevel->priv->table),
 
1315
                          button,
 
1316
                          left_attach,
 
1317
                          right_attach,
 
1318
                          top_attach,
 
1319
                          bottom_attach,
 
1320
                          GTK_FILL,
 
1321
                          GTK_FILL,
 
1322
                          0,
 
1323
                          0);
 
1324
 
 
1325
        return button;
 
1326
}
 
1327
 
 
1328
static void
 
1329
panel_toplevel_update_buttons_showing (PanelToplevel *toplevel)
 
1330
{
 
1331
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 
1332
                gtk_widget_hide (toplevel->priv->hide_button_top);
 
1333
                gtk_widget_hide (toplevel->priv->hide_button_bottom);
 
1334
                gtk_widget_show (toplevel->priv->hide_button_left);
 
1335
                gtk_widget_show (toplevel->priv->hide_button_right);
 
1336
        } else {
 
1337
                gtk_widget_show (toplevel->priv->hide_button_top);
 
1338
                gtk_widget_show (toplevel->priv->hide_button_bottom);
 
1339
                gtk_widget_hide (toplevel->priv->hide_button_left);
 
1340
                gtk_widget_hide (toplevel->priv->hide_button_right);
 
1341
        }
 
1342
}
 
1343
 
 
1344
static void
 
1345
panel_toplevel_update_hide_buttons (PanelToplevel *toplevel)
 
1346
{
 
1347
        if (toplevel->priv->buttons_enabled)
 
1348
                panel_toplevel_update_buttons_showing (toplevel);
 
1349
        else {
 
1350
                g_object_set (
 
1351
                        G_OBJECT (toplevel->priv->hide_button_top),
 
1352
                        "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_DOWN,
 
1353
                        NULL);
 
1354
                g_object_set (
 
1355
                        G_OBJECT (toplevel->priv->hide_button_bottom),
 
1356
                        "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_UP,
 
1357
                        NULL);
 
1358
                g_object_set (
 
1359
                        G_OBJECT (toplevel->priv->hide_button_left),
 
1360
                        "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_RIGHT,
 
1361
                        NULL);
 
1362
                g_object_set (
 
1363
                        G_OBJECT (toplevel->priv->hide_button_right),
 
1364
                        "visible", toplevel->priv->state == PANEL_STATE_HIDDEN_LEFT,
 
1365
                        NULL);
 
1366
        }
 
1367
 
 
1368
        if (toplevel->priv->arrows_enabled) {
 
1369
                int arrow_size;
 
1370
 
 
1371
                gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_top)));
 
1372
                gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_bottom)));
 
1373
                gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_left)));
 
1374
                gtk_widget_show (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_right)));
 
1375
 
 
1376
                gtk_widget_style_get (GTK_WIDGET (toplevel),
 
1377
                                      "arrow-size", &arrow_size,
 
1378
                                      NULL);
 
1379
 
 
1380
                gtk_widget_set_size_request (toplevel->priv->hide_button_top,
 
1381
                                             -1, arrow_size);
 
1382
                gtk_widget_set_size_request (toplevel->priv->hide_button_bottom,
 
1383
                                             -1, arrow_size);
 
1384
                gtk_widget_set_size_request (toplevel->priv->hide_button_left,
 
1385
                                             arrow_size, -1);
 
1386
                gtk_widget_set_size_request (toplevel->priv->hide_button_right,
 
1387
                                             arrow_size, -1);
 
1388
        } else {
 
1389
                gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_top)));
 
1390
                gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_bottom)));
 
1391
                gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_left)));
 
1392
                gtk_widget_hide (gtk_bin_get_child (GTK_BIN (toplevel->priv->hide_button_right)));
 
1393
 
 
1394
                gtk_widget_set_size_request (toplevel->priv->hide_button_top,    -1, -1);
 
1395
                gtk_widget_set_size_request (toplevel->priv->hide_button_bottom, -1, -1);
 
1396
                gtk_widget_set_size_request (toplevel->priv->hide_button_left,   -1, -1);
 
1397
                gtk_widget_set_size_request (toplevel->priv->hide_button_right,  -1, -1);
 
1398
        }
 
1399
}
 
1400
 
 
1401
static gboolean
 
1402
panel_toplevel_contains_pointer (PanelToplevel *toplevel)
 
1403
{
 
1404
        GdkDisplay *display;
 
1405
        GdkScreen  *screen;
 
1406
        GtkWidget  *widget;
 
1407
        GdkDeviceManager *device_manager;
 
1408
        GdkDevice  *pointer;
 
1409
        int         x, y;
 
1410
 
 
1411
        display = gdk_display_get_default ();
 
1412
        device_manager = gdk_display_get_device_manager (display);
 
1413
        pointer = gdk_device_manager_get_client_pointer (device_manager);
 
1414
        widget  = GTK_WIDGET (toplevel);
 
1415
 
 
1416
        if (!gtk_widget_get_realized (widget))
 
1417
                return FALSE;
 
1418
 
 
1419
        screen = NULL;
 
1420
        x = y = -1;
 
1421
        gdk_device_get_position (pointer, &screen, &x, &y);
 
1422
 
 
1423
        if (screen != gtk_window_get_screen (GTK_WINDOW (toplevel)))
 
1424
                return FALSE;
 
1425
 
 
1426
        if (x == -1 || y == -1)
 
1427
                return FALSE;
 
1428
 
 
1429
        if (x < toplevel->priv->geometry.x || x >= (toplevel->priv->geometry.x + toplevel->priv->geometry.width) ||
 
1430
            y < toplevel->priv->geometry.y || y >= (toplevel->priv->geometry.y + toplevel->priv->geometry.height))
 
1431
                return FALSE;
 
1432
 
 
1433
        return TRUE;
 
1434
}
 
1435
 
 
1436
static inline int
 
1437
panel_toplevel_get_effective_auto_hide_size (PanelToplevel *toplevel)
 
1438
{
 
1439
        int size;
 
1440
 
 
1441
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)
 
1442
                size = CLAMP (toplevel->priv->auto_hide_size,
 
1443
                              1, toplevel->priv->original_height / 2);
 
1444
        else
 
1445
                size = CLAMP (toplevel->priv->auto_hide_size,
 
1446
                              1, toplevel->priv->original_width / 2);
 
1447
 
 
1448
        /* paranoia */
 
1449
        return (size <= 0) ? DEFAULT_AUTO_HIDE_SIZE : size;
 
1450
}
 
1451
 
 
1452
static gboolean
 
1453
panel_toplevel_update_struts (PanelToplevel *toplevel, gboolean end_of_animation)
 
1454
{
 
1455
        PanelOrientation  orientation;
 
1456
        GdkScreen        *screen;
 
1457
        gboolean          geometry_changed = FALSE;
 
1458
        int               strut, strut_start, strut_end;
 
1459
        int               x, y, width, height;
 
1460
        int               monitor_x, monitor_y;
 
1461
        int               monitor_width, monitor_height;
 
1462
 
 
1463
        if (!toplevel->priv->updated_geometry_initial)
 
1464
                return FALSE;
 
1465
 
 
1466
        /* In the case of the initial animation, we really want the struts to
 
1467
         * represent what is at the end of the animation, to avoid desktop
 
1468
         * icons jumping around. */
 
1469
        if (!toplevel->priv->initial_animation_done) {
 
1470
                end_of_animation = TRUE;
 
1471
 
 
1472
                /* We've not started the animation yet, so we have to compute
 
1473
                 * where we want to end. Note that we don't want to compute
 
1474
                 * this everytime, since the struts conflict resolution will be
 
1475
                 * overridden if we do so */
 
1476
                if (!toplevel->priv->animating)
 
1477
                        panel_toplevel_calculate_animation_end_geometry (toplevel);
 
1478
        }
 
1479
 
 
1480
        screen = panel_toplevel_get_monitor_geometry (toplevel,
 
1481
                                                      &monitor_x,
 
1482
                                                      &monitor_y,
 
1483
                                                      &monitor_width,
 
1484
                                                      &monitor_height);
 
1485
 
 
1486
        if (end_of_animation) {
 
1487
                x = toplevel->priv->animation_end_x;
 
1488
                y = toplevel->priv->animation_end_y;
 
1489
                x += panel_multiscreen_x (screen, toplevel->priv->monitor);
 
1490
                y += panel_multiscreen_y (screen, toplevel->priv->monitor);
 
1491
                if (toplevel->priv->animation_end_width != -1)
 
1492
                        width = toplevel->priv->animation_end_width;
 
1493
                else
 
1494
                        width = toplevel->priv->geometry.width;
 
1495
                if (toplevel->priv->animation_end_height != -1)
 
1496
                        height = toplevel->priv->animation_end_height;
 
1497
                else
 
1498
                        height = toplevel->priv->geometry.height;
 
1499
        } else {
 
1500
                x      = toplevel->priv->geometry.x;
 
1501
                y      = toplevel->priv->geometry.y;
 
1502
                width  = toplevel->priv->geometry.width;
 
1503
                height = toplevel->priv->geometry.height;
 
1504
        }
 
1505
 
 
1506
        orientation = toplevel->priv->orientation;
 
1507
 
 
1508
        strut = strut_start = strut_end = 0;
 
1509
 
 
1510
        if (orientation & PANEL_HORIZONTAL_MASK) {
 
1511
                if (y <= monitor_y) {
 
1512
                        orientation = PANEL_ORIENTATION_TOP;
 
1513
                        strut = y + height - monitor_y;
 
1514
                } else if (y >= monitor_y + monitor_height - height) {
 
1515
                        orientation = PANEL_ORIENTATION_BOTTOM;
 
1516
                        strut = monitor_y + monitor_height - y;
 
1517
                }
 
1518
 
 
1519
                if (strut > 0) {
 
1520
                        strut_start = MAX (x, monitor_x);
 
1521
                        strut_end = MIN (x + width, monitor_x + monitor_width) - 1;
 
1522
                }
 
1523
        } else {
 
1524
                if (x <= monitor_x) {
 
1525
                        orientation = PANEL_ORIENTATION_LEFT;
 
1526
                        strut = x + width - monitor_x;
 
1527
                } else if (x >= monitor_x + monitor_width - width) {
 
1528
                        orientation = PANEL_ORIENTATION_RIGHT;
 
1529
                        strut = monitor_x + monitor_width - x;
 
1530
                }
 
1531
 
 
1532
                if (strut > 0) {
 
1533
                        strut_start = MAX (y, monitor_y);
 
1534
                        strut_end = MIN (y + height, monitor_y + monitor_height) - 1;
 
1535
                }
 
1536
        }
 
1537
 
 
1538
        if (orientation != toplevel->priv->orientation) {
 
1539
                toplevel->priv->orientation = orientation;
 
1540
                g_object_notify (G_OBJECT (toplevel), "orientation");
 
1541
        }
 
1542
 
 
1543
        if (toplevel->priv->auto_hide && strut > 0)
 
1544
                strut = panel_toplevel_get_effective_auto_hide_size (toplevel);
 
1545
 
 
1546
        if (strut > 0)
 
1547
                geometry_changed = panel_struts_register_strut (toplevel,
 
1548
                                                                screen,
 
1549
                                                                toplevel->priv->monitor,
 
1550
                                                                orientation,
 
1551
                                                                strut,
 
1552
                                                                strut_start,
 
1553
                                                                strut_end);
 
1554
        else
 
1555
                panel_struts_unregister_strut (toplevel);
 
1556
 
 
1557
        if (toplevel->priv->state == PANEL_STATE_NORMAL ||
 
1558
            toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN ||
 
1559
            toplevel->priv->animating)
 
1560
                panel_struts_set_window_hint (toplevel);
 
1561
        else
 
1562
                panel_struts_unset_window_hint (toplevel);
 
1563
 
 
1564
        return geometry_changed;
 
1565
}
 
1566
 
 
1567
void
 
1568
panel_toplevel_update_edges (PanelToplevel *toplevel)
 
1569
{
 
1570
        GtkWidget       *widget;
 
1571
        PanelFrameEdge   edges;
 
1572
        PanelFrameEdge   inner_edges;
 
1573
        PanelFrameEdge   outer_edges;
 
1574
        PanelBackground *background;
 
1575
        int              monitor_width, monitor_height;
 
1576
        int              width, height;
 
1577
        gboolean         inner_frame = FALSE;
 
1578
 
 
1579
        widget = GTK_WIDGET (toplevel);
 
1580
 
 
1581
        panel_toplevel_get_monitor_geometry (
 
1582
                        toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
1583
 
 
1584
        width  = toplevel->priv->geometry.width;
 
1585
        height = toplevel->priv->geometry.height;
 
1586
 
 
1587
        edges = PANEL_EDGE_NONE;
 
1588
 
 
1589
        background = &toplevel->priv->panel_widget->background;
 
1590
 
 
1591
        /* We don't want any bevels with a color/image background */
 
1592
        if (panel_background_effective_type (background) == PANEL_BACK_NONE) {
 
1593
                if (toplevel->priv->geometry.y > 0)
 
1594
                        edges |= PANEL_EDGE_TOP;
 
1595
 
 
1596
                if (toplevel->priv->geometry.x > 0)
 
1597
                        edges |= PANEL_EDGE_LEFT;
 
1598
 
 
1599
                if (toplevel->priv->geometry.y < (monitor_height - height))
 
1600
                        edges |= PANEL_EDGE_BOTTOM;
 
1601
 
 
1602
                if (toplevel->priv->geometry.x < (monitor_width - width))
 
1603
                        edges |= PANEL_EDGE_RIGHT;
 
1604
 
 
1605
                /* There is a conflict in the position algorithm when a
 
1606
                 * non-expanded centered panel is nearly the size of the
 
1607
                 * screen. This is similar to the one we have in
 
1608
                 * panel_toplevel_update_position(). A simple solution is
 
1609
                 * to keep the bevels in this case. */
 
1610
                if (!toplevel->priv->expand &&
 
1611
                    toplevel->priv->orientation & PANEL_HORIZONTAL_MASK &&
 
1612
                    toplevel->priv->x_centered)
 
1613
                        edges |= PANEL_EDGE_LEFT | PANEL_EDGE_RIGHT;
 
1614
 
 
1615
                if (!toplevel->priv->expand &&
 
1616
                    toplevel->priv->orientation & PANEL_VERTICAL_MASK &&
 
1617
                    toplevel->priv->y_centered)
 
1618
                        edges |= PANEL_EDGE_TOP | PANEL_EDGE_BOTTOM;
 
1619
 
 
1620
                if (gtk_widget_get_visible (toplevel->priv->hide_button_left) ||
 
1621
                    gtk_widget_get_visible (toplevel->priv->hide_button_right)) {
 
1622
                        inner_frame = TRUE;
 
1623
                        edges |= PANEL_EDGE_LEFT | PANEL_EDGE_RIGHT;
 
1624
                }
 
1625
 
 
1626
                if (gtk_widget_get_visible (toplevel->priv->hide_button_top) ||
 
1627
                    gtk_widget_get_visible (toplevel->priv->hide_button_bottom)) {
 
1628
                        inner_frame = TRUE;
 
1629
                        edges |= PANEL_EDGE_TOP | PANEL_EDGE_BOTTOM;
 
1630
                }
 
1631
        }
 
1632
 
 
1633
        if (!inner_frame) {
 
1634
                inner_edges = PANEL_EDGE_NONE;
 
1635
                outer_edges = edges;
 
1636
        } else {
 
1637
                inner_edges = edges;
 
1638
                outer_edges = PANEL_EDGE_NONE;
 
1639
        }
 
1640
 
 
1641
        panel_frame_set_edges (toplevel->priv->inner_frame, inner_edges);
 
1642
 
 
1643
        if (toplevel->priv->edges != outer_edges) {
 
1644
                toplevel->priv->edges = outer_edges;
 
1645
                gtk_widget_queue_resize (widget);
 
1646
        }
 
1647
}
 
1648
 
 
1649
static const char *
 
1650
panel_toplevel_construct_description (PanelToplevel *toplevel)
 
1651
{
 
1652
        int orientation, type;
 
1653
 
 
1654
        static const char *description[4][4] = {
 
1655
                {
 
1656
        /* translators: these string will be shown in MetaCity's switch window
 
1657
         * popup when you pass the focus to a panel */
 
1658
                        N_("Top Expanded Edge Panel"),
 
1659
                        N_("Top Centered Panel"),
 
1660
                        N_("Top Floating Panel"),
 
1661
                        N_("Top Edge Panel"),
 
1662
                },
 
1663
                
 
1664
                {
 
1665
                        N_("Bottom Expanded Edge Panel"),
 
1666
                        N_("Bottom Centered Panel"),
 
1667
                        N_("Bottom Floating Panel"),
 
1668
                        N_("Bottom Edge Panel"),
 
1669
                },
 
1670
 
 
1671
                {
 
1672
                        N_("Left Expanded Edge Panel"),
 
1673
                        N_("Left Centered Panel"),
 
1674
                        N_("Left Floating Panel"),
 
1675
                        N_("Left Edge Panel"),
 
1676
                },
 
1677
 
 
1678
                {
 
1679
                        N_("Right Expanded Edge Panel"),
 
1680
                        N_("Right Centered Panel"),
 
1681
                        N_("Right Floating Panel"),
 
1682
                        N_("Right Edge Panel"),
 
1683
                },
 
1684
        };
 
1685
 
 
1686
        switch (toplevel->priv->orientation) {
 
1687
        case PANEL_ORIENTATION_TOP:
 
1688
                orientation = 0;
 
1689
                break;
 
1690
        case PANEL_ORIENTATION_BOTTOM:
 
1691
                orientation = 1;
 
1692
                break;
 
1693
        case PANEL_ORIENTATION_LEFT:
 
1694
                orientation = 2;
 
1695
                break;
 
1696
        case PANEL_ORIENTATION_RIGHT:
 
1697
                orientation = 3;
 
1698
                break;
 
1699
        default:
 
1700
                orientation = 0;
 
1701
                g_assert_not_reached ();
 
1702
                break;
 
1703
        }
 
1704
 
 
1705
        if (toplevel->priv->expand)
 
1706
                type = 0;
 
1707
        else if (toplevel->priv->x_centered ||
 
1708
                 toplevel->priv->y_centered)
 
1709
                type = 1;
 
1710
        else if (toplevel->priv->floating)
 
1711
                type = 2;
 
1712
        else
 
1713
                type = 3;
 
1714
        
 
1715
        return description[orientation][type];
 
1716
}
 
1717
 
 
1718
static void
 
1719
panel_toplevel_update_description (PanelToplevel *toplevel)
 
1720
{
 
1721
        const char *description;
 
1722
 
 
1723
        description = panel_toplevel_construct_description (toplevel);
 
1724
 
 
1725
        if (toplevel->priv->description &&
 
1726
            !strcmp (toplevel->priv->description, description))
 
1727
                return;
 
1728
 
 
1729
        if (toplevel->priv->description)
 
1730
                g_free (toplevel->priv->description);
 
1731
        toplevel->priv->description = g_strdup (_(description));
 
1732
 
 
1733
        if (!toplevel->priv->name)
 
1734
                gtk_window_set_title (GTK_WINDOW (toplevel),
 
1735
                                      toplevel->priv->description);
 
1736
 
 
1737
        panel_a11y_set_atk_name_desc (
 
1738
                GTK_WIDGET (toplevel->priv->panel_widget),
 
1739
                toplevel->priv->name ? toplevel->priv->name :
 
1740
                                       _(toplevel->priv->description),
 
1741
                _(toplevel->priv->description));
 
1742
}
 
1743
 
 
1744
static void
 
1745
panel_toplevel_update_normal_position (PanelToplevel *toplevel,
 
1746
                                       int           *x,
 
1747
                                       int           *y,
 
1748
                                       int           *w,
 
1749
                                       int           *h)
 
1750
{
 
1751
        int        monitor_width, monitor_height;
 
1752
        int        width, height;
 
1753
        int        snap_tolerance;
 
1754
 
 
1755
        g_assert (x != NULL && y != NULL);
 
1756
 
 
1757
        panel_toplevel_get_monitor_geometry (
 
1758
                        toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
1759
 
 
1760
        width  = toplevel->priv->original_width;
 
1761
        height = toplevel->priv->original_height;
 
1762
        snap_tolerance = toplevel->priv->snap_tolerance;
 
1763
 
 
1764
        *x = CLAMP (*x, 0, monitor_width  - width);
 
1765
        *y = CLAMP (*y, 0, monitor_height - height);
 
1766
 
 
1767
        if (toplevel->priv->x <= snap_tolerance &&
 
1768
            toplevel->priv->x_right == -1 &&
 
1769
            !toplevel->priv->x_centered)
 
1770
                *x = 0;
 
1771
        else if (toplevel->priv->x_right != -1 &&
 
1772
                 toplevel->priv->x_right <= snap_tolerance &&
 
1773
                 !toplevel->priv->x_centered)
 
1774
                *x = monitor_width - width;
 
1775
 
 
1776
        if (toplevel->priv->y <= snap_tolerance &&
 
1777
            toplevel->priv->y_bottom == -1 &&
 
1778
            !toplevel->priv->y_centered)
 
1779
                *y = 0;
 
1780
        else if (toplevel->priv->y_bottom != -1 &&
 
1781
                 toplevel->priv->y_bottom <= snap_tolerance &&
 
1782
                 !toplevel->priv->y_centered)
 
1783
                *y = monitor_height - height;
 
1784
}
 
1785
 
 
1786
static void
 
1787
panel_toplevel_update_auto_hide_position (PanelToplevel *toplevel,
 
1788
                                          int           *x,
 
1789
                                          int           *y,
 
1790
                                          int           *w,
 
1791
                                          int           *h,
 
1792
                                          gboolean       for_end_position)
 
1793
{
 
1794
        int width, height;
 
1795
        int monitor_width, monitor_height;
 
1796
        int auto_hide_size;
 
1797
        int snap_tolerance;
 
1798
 
 
1799
        g_assert (x != NULL && y != NULL);
 
1800
 
 
1801
        if (toplevel->priv->floating) {
 
1802
                panel_toplevel_update_normal_position (toplevel, x, y, w, h);
 
1803
                return;
 
1804
        }
 
1805
 
 
1806
        panel_toplevel_get_monitor_geometry (
 
1807
                        toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
1808
 
 
1809
        width  = toplevel->priv->original_width;
 
1810
        height = toplevel->priv->original_height;
 
1811
        snap_tolerance = toplevel->priv->snap_tolerance;
 
1812
 
 
1813
        /* For the initial animation, we animate from outside the screen, and
 
1814
         * so we don't want the toplevel to be visible at all. But when the
 
1815
         * request is for the end position, then we give the real result (it's
 
1816
         * useful for struts) */
 
1817
        if (for_end_position || toplevel->priv->initial_animation_done) {
 
1818
                auto_hide_size = panel_toplevel_get_effective_auto_hide_size (toplevel);
 
1819
        } else {
 
1820
                auto_hide_size = 0;
 
1821
        }
 
1822
 
 
1823
        switch (toplevel->priv->orientation) {
 
1824
        case PANEL_ORIENTATION_TOP:
 
1825
                *y = - (height - auto_hide_size);
 
1826
                break;
 
1827
        case PANEL_ORIENTATION_BOTTOM:
 
1828
                *y = monitor_height - auto_hide_size;
 
1829
                break;
 
1830
        case PANEL_ORIENTATION_LEFT:
 
1831
                *x = - (width - auto_hide_size);
 
1832
                break;
 
1833
        case PANEL_ORIENTATION_RIGHT:
 
1834
                *x = monitor_width - auto_hide_size;
 
1835
                break;
 
1836
        default:
 
1837
                g_assert_not_reached ();
 
1838
                break;
 
1839
        }
 
1840
 
 
1841
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 
1842
                if (toplevel->priv->x <= snap_tolerance &&
 
1843
                    toplevel->priv->x_right == -1 &&
 
1844
                    !toplevel->priv->x_centered)
 
1845
                        *x = 0;
 
1846
                else if (toplevel->priv->x_right != -1 &&
 
1847
                         toplevel->priv->x_right <= snap_tolerance &&
 
1848
                         !toplevel->priv->x_centered)
 
1849
                        *x = monitor_width - width;
 
1850
        } else /* if (toplevel->priv->orientation & PANEL_VERTICAL_MASK) */ {
 
1851
                if (toplevel->priv->y <= snap_tolerance &&
 
1852
                    toplevel->priv->y_bottom == -1 &&
 
1853
                    !toplevel->priv->y_centered)
 
1854
                        *y = 0;
 
1855
                else if (toplevel->priv->y_bottom != -1 &&
 
1856
                         toplevel->priv->y_bottom <= snap_tolerance &&
 
1857
                         !toplevel->priv->y_centered)
 
1858
                        *y = monitor_height - height;
 
1859
        }
 
1860
}
 
1861
 
 
1862
/* FIXME: this is wrong for Xinerama. In the Xinerama case
 
1863
 *        I think if hiding it requires it to go onto the
 
1864
 *        next monitor then it should just move it on to
 
1865
 *        the next monitor and set its state back to normal
 
1866
 */
 
1867
static void
 
1868
panel_toplevel_update_hidden_position (PanelToplevel *toplevel,
 
1869
                                       int           *x,
 
1870
                                       int           *y,
 
1871
                                       int           *w,
 
1872
                                       int           *h)
 
1873
{
 
1874
        int width, height;
 
1875
        int min_hide_size;
 
1876
        int monitor_height, monitor_width;
 
1877
        GtkAllocation hide_allocation;
 
1878
 
 
1879
        g_assert (x != NULL && y != NULL);
 
1880
 
 
1881
        g_assert (toplevel->priv->state == PANEL_STATE_HIDDEN_UP   ||
 
1882
                  toplevel->priv->state == PANEL_STATE_HIDDEN_DOWN ||
 
1883
                  toplevel->priv->state == PANEL_STATE_HIDDEN_LEFT ||
 
1884
                  toplevel->priv->state == PANEL_STATE_HIDDEN_RIGHT);
 
1885
 
 
1886
        panel_toplevel_get_monitor_geometry (
 
1887
                        toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
1888
 
 
1889
        width  = toplevel->priv->original_width;
 
1890
        height = toplevel->priv->original_height;
 
1891
 
 
1892
        //FIXME should find a better default
 
1893
        min_hide_size = DEFAULT_AUTO_HIDE_SIZE;
 
1894
 
 
1895
        switch (toplevel->priv->state) {
 
1896
        case PANEL_STATE_HIDDEN_UP:
 
1897
                gtk_widget_get_allocation (toplevel->priv->hide_button_bottom,
 
1898
                                           &hide_allocation);
 
1899
                *y = - (height - MAX (hide_allocation.height, min_hide_size));
 
1900
                break;
 
1901
        case PANEL_STATE_HIDDEN_DOWN:
 
1902
                gtk_widget_get_allocation (toplevel->priv->hide_button_top,
 
1903
                                           &hide_allocation);
 
1904
                *y = monitor_height - MAX (hide_allocation.height, min_hide_size);
 
1905
                break;
 
1906
        case PANEL_STATE_HIDDEN_LEFT:
 
1907
                gtk_widget_get_allocation (toplevel->priv->hide_button_right,
 
1908
                                           &hide_allocation);
 
1909
                *x = - (width - MAX (hide_allocation.width, min_hide_size));
 
1910
                break;
 
1911
        case PANEL_STATE_HIDDEN_RIGHT:
 
1912
                gtk_widget_get_allocation (toplevel->priv->hide_button_left,
 
1913
                                           &hide_allocation);
 
1914
                *x = monitor_width - MAX (hide_allocation.width, min_hide_size);
 
1915
                break;
 
1916
        default:
 
1917
                g_assert_not_reached ();
 
1918
                break;
 
1919
        }
 
1920
}
 
1921
 
 
1922
/*
 
1923
 * This is "almost" like the double sine movement
 
1924
 * from the original panel except that it uses
 
1925
 * a cubic (twice again).  I suppose it looks less
 
1926
 * mathematical now :) -- _v_
 
1927
 */
 
1928
static int
 
1929
get_delta (int       src,
 
1930
           int       dest,
 
1931
           GTimeVal *start_time,
 
1932
           GTimeVal *end_time,
 
1933
           GTimeVal *cur_time)
 
1934
{
 
1935
        double x, s, n, d, percentage;
 
1936
 
 
1937
        s = start_time->tv_sec + ((double)start_time->tv_usec / G_USEC_PER_SEC);
 
1938
        n = cur_time->tv_sec + ((double)cur_time->tv_usec / G_USEC_PER_SEC);
 
1939
        d = end_time->tv_sec + ((double)end_time->tv_usec / G_USEC_PER_SEC);
 
1940
 
 
1941
        n -= s;
 
1942
        d -= s;
 
1943
 
 
1944
        if (abs (dest - src) <= 1 || n >= d)
 
1945
                return dest - src;
 
1946
 
 
1947
        /* The cubic is: p(x) = (-2) x^2 (x-1.5) */
 
1948
        /* running p(p(x)) to make it more "pronounced",
 
1949
         * effectively making it a ninth-degree polynomial */
 
1950
 
 
1951
        x = (double)n/d;
 
1952
        x = -2 * (x*x) * (x-1.5);
 
1953
        /* run it again */
 
1954
        percentage = -2 * (x*x) * (x-1.5);
 
1955
 
 
1956
        percentage = CLAMP (percentage, 0.0, 1.0);
 
1957
 
 
1958
        return ((dest - src) * percentage);
 
1959
}
 
1960
 
 
1961
static void
 
1962
panel_toplevel_update_animating_position (PanelToplevel *toplevel)
 
1963
{
 
1964
        GdkScreen *screen;
 
1965
        GTimeVal   time_val;
 
1966
        int        deltax, deltay, deltaw = 0, deltah = 0;
 
1967
        int        monitor_offset_x, monitor_offset_y;
 
1968
 
 
1969
        g_get_current_time (&time_val);
 
1970
 
 
1971
        screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
1972
 
 
1973
        monitor_offset_x = panel_multiscreen_x (screen, toplevel->priv->monitor);
 
1974
        monitor_offset_y = panel_multiscreen_y (screen, toplevel->priv->monitor);
 
1975
 
 
1976
        if (toplevel->priv->animation_end_width != -1)
 
1977
                deltaw = get_delta (toplevel->priv->geometry.width,
 
1978
                                    toplevel->priv->animation_end_width,
 
1979
                                    &toplevel->priv->animation_start_time,
 
1980
                                    &toplevel->priv->animation_end_time,
 
1981
                                    &time_val);
 
1982
 
 
1983
        if (toplevel->priv->animation_end_height != -1)
 
1984
                deltah = get_delta (toplevel->priv->geometry.height,
 
1985
                                    toplevel->priv->animation_end_height,
 
1986
                                    &toplevel->priv->animation_start_time,
 
1987
                                    &toplevel->priv->animation_end_time,
 
1988
                                    &time_val);
 
1989
 
 
1990
        deltax = get_delta (toplevel->priv->geometry.x - monitor_offset_x,
 
1991
                            toplevel->priv->animation_end_x,
 
1992
                            &toplevel->priv->animation_start_time,
 
1993
                            &toplevel->priv->animation_end_time,
 
1994
                            &time_val);
 
1995
 
 
1996
        deltay = get_delta (toplevel->priv->geometry.y - monitor_offset_y,
 
1997
                            toplevel->priv->animation_end_y,
 
1998
                            &toplevel->priv->animation_start_time,
 
1999
                            &toplevel->priv->animation_end_time,
 
2000
                            &time_val);
 
2001
 
 
2002
        if (deltaw != 0 && abs (deltaw) > abs (deltax))
 
2003
                deltax = deltaw;
 
2004
        if (deltah != 0 && abs (deltah) > abs (deltay))
 
2005
                deltay = deltah;
 
2006
 
 
2007
        toplevel->priv->geometry.x += deltax;
 
2008
        toplevel->priv->geometry.y += deltay;
 
2009
 
 
2010
        toplevel->priv->geometry.width += deltaw;
 
2011
        toplevel->priv->geometry.height += deltah;
 
2012
 
 
2013
        if (toplevel->priv->geometry.x - monitor_offset_x == toplevel->priv->animation_end_x &&
 
2014
            toplevel->priv->geometry.y - monitor_offset_y == toplevel->priv->animation_end_y) {
 
2015
                toplevel->priv->animating = FALSE;
 
2016
                /* Note: it's important to set initial_animation_done to TRUE
 
2017
                 * as soon as possible (hence, here) since we don't want to
 
2018
                 * have a wrong value in a size request event */
 
2019
                toplevel->priv->initial_animation_done = TRUE;
 
2020
 
 
2021
                gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
2022
 
 
2023
                if (toplevel->priv->state == PANEL_STATE_NORMAL)
 
2024
                        g_signal_emit (toplevel, toplevel_signals [UNHIDE_SIGNAL], 0);
 
2025
        }
 
2026
}
 
2027
 
 
2028
static void
 
2029
panel_toplevel_update_expanded_position (PanelToplevel *toplevel)
 
2030
{
 
2031
        GdkScreen *screen;
 
2032
        int        monitor_width, monitor_height;
 
2033
        int        screen_width, screen_height;
 
2034
        int        monitor_x, monitor_y;
 
2035
        int        x, y;
 
2036
        int        x_right, y_bottom;
 
2037
        int        monitor;
 
2038
 
 
2039
        if (!toplevel->priv->expand)
 
2040
                return;
 
2041
 
 
2042
        screen = panel_toplevel_get_screen_geometry (toplevel,
 
2043
                                                     &screen_width,
 
2044
                                                     &screen_height);
 
2045
 
 
2046
        panel_toplevel_get_monitor_geometry (toplevel, &monitor_x, &monitor_y,
 
2047
                                             &monitor_width, &monitor_height);
 
2048
 
 
2049
        x = -1;
 
2050
        y = -1;
 
2051
        x_right = -1;
 
2052
        y_bottom = -1;
 
2053
 
 
2054
        switch (toplevel->priv->orientation) {
 
2055
        case PANEL_ORIENTATION_TOP:
 
2056
                x = monitor_x;
 
2057
                y = monitor_y;
 
2058
                break;
 
2059
        case PANEL_ORIENTATION_LEFT:
 
2060
                x = monitor_x;
 
2061
                y = monitor_y;
 
2062
                break;
 
2063
        case PANEL_ORIENTATION_BOTTOM:
 
2064
                x = monitor_x;
 
2065
                y = monitor_y + monitor_height - toplevel->priv->geometry.height;
 
2066
                y_bottom = 0;
 
2067
                break;
 
2068
        case PANEL_ORIENTATION_RIGHT:
 
2069
                x = monitor_x + monitor_width - toplevel->priv->geometry.width;
 
2070
                y = monitor_y;
 
2071
                x_right = 0;
 
2072
                break;
 
2073
        default:
 
2074
                g_assert_not_reached ();
 
2075
                break;
 
2076
        }
 
2077
 
 
2078
        monitor = panel_multiscreen_get_monitor_at_point (screen, x, y);
 
2079
 
 
2080
        panel_toplevel_set_monitor_internal (toplevel, monitor, TRUE);
 
2081
 
 
2082
        x -= panel_multiscreen_x (screen, monitor);
 
2083
        y -= panel_multiscreen_y (screen, monitor);
 
2084
 
 
2085
        g_object_freeze_notify (G_OBJECT (toplevel));
 
2086
 
 
2087
        if (toplevel->priv->x != x) {
 
2088
                toplevel->priv->x = x;
 
2089
                g_object_notify (G_OBJECT (toplevel), "x");
 
2090
        }
 
2091
 
 
2092
        if (toplevel->priv->y != y) {
 
2093
                toplevel->priv->y = y;
 
2094
                g_object_notify (G_OBJECT (toplevel), "y");
 
2095
        }
 
2096
 
 
2097
        if (toplevel->priv->x_right != x_right) {
 
2098
                toplevel->priv->x_right = x_right;
 
2099
                g_object_notify (G_OBJECT (toplevel), "x_right");
 
2100
        }
 
2101
 
 
2102
        if (toplevel->priv->y_bottom != y_bottom) {
 
2103
                toplevel->priv->y_bottom = y_bottom;
 
2104
                g_object_notify (G_OBJECT (toplevel), "y_bottom");
 
2105
        }
 
2106
 
 
2107
        g_object_thaw_notify (G_OBJECT (toplevel));
 
2108
}
 
2109
 
 
2110
static void
 
2111
panel_toplevel_update_position (PanelToplevel *toplevel)
 
2112
{
 
2113
        PanelBackground *background;
 
2114
        GdkScreen       *screen;
 
2115
        int              x, y;
 
2116
        int              w, h;
 
2117
        int              screen_width, screen_height;
 
2118
        int              monitor_width, monitor_height;
 
2119
 
 
2120
        screen = panel_toplevel_get_screen_geometry (
 
2121
                        toplevel, &screen_width, &screen_height);
 
2122
 
 
2123
        panel_toplevel_get_monitor_geometry (
 
2124
                        toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
2125
 
 
2126
        if (toplevel->priv->animating) {
 
2127
                panel_toplevel_update_animating_position (toplevel);
 
2128
                return;
 
2129
        }
 
2130
 
 
2131
        if (toplevel->priv->position_centered) {
 
2132
                toplevel->priv->position_centered = FALSE;
 
2133
 
 
2134
                g_object_freeze_notify (G_OBJECT (toplevel));
 
2135
 
 
2136
                if (!toplevel->priv->x_centered) {
 
2137
                        int x_right;
 
2138
 
 
2139
                        toplevel->priv->x -= toplevel->priv->geometry.width  / 2;
 
2140
                        g_object_notify (G_OBJECT (toplevel), "x");
 
2141
 
 
2142
                        if ((toplevel->priv->x + toplevel->priv->geometry.width / 2) > monitor_width / 2)
 
2143
                                x_right = monitor_width - (toplevel->priv->x + toplevel->priv->geometry.width);
 
2144
                        else
 
2145
                                x_right = -1;
 
2146
                        if (toplevel->priv->x_right != x_right) {
 
2147
                                toplevel->priv->x_right = x_right;
 
2148
                                g_object_notify (G_OBJECT (toplevel),
 
2149
                                                 "x-right");
 
2150
                        }
 
2151
                }
 
2152
 
 
2153
                if (!toplevel->priv->y_centered) {
 
2154
                        int y_bottom;
 
2155
 
 
2156
                        toplevel->priv->y -= toplevel->priv->geometry.height / 2;
 
2157
                        g_object_notify (G_OBJECT (toplevel), "y");
 
2158
 
 
2159
                        if ((toplevel->priv->y + toplevel->priv->geometry.height / 2) > monitor_height / 2)
 
2160
                                y_bottom = monitor_height - (toplevel->priv->y + toplevel->priv->geometry.height);
 
2161
                        else
 
2162
                                y_bottom = -1;
 
2163
                        if (toplevel->priv->y_bottom != y_bottom) {
 
2164
                                toplevel->priv->y_bottom = y_bottom;
 
2165
                                g_object_notify (G_OBJECT (toplevel),
 
2166
                                                 "y-bottom");
 
2167
                        }
 
2168
                }
 
2169
 
 
2170
                g_object_thaw_notify (G_OBJECT (toplevel));
 
2171
        }
 
2172
 
 
2173
        panel_toplevel_update_expanded_position (toplevel);
 
2174
        panel_toplevel_calc_floating (toplevel); //FIXME should probably be done after panel_toplevel_update_normal_position() too
 
2175
 
 
2176
        if (toplevel->priv->x_right == -1)
 
2177
                x = toplevel->priv->x;
 
2178
        else
 
2179
                x = monitor_width - (toplevel->priv->x_right + toplevel->priv->geometry.width);
 
2180
        if (toplevel->priv->y_bottom == -1)
 
2181
                y = toplevel->priv->y;
 
2182
        else
 
2183
                y = monitor_height - (toplevel->priv->y_bottom + toplevel->priv->geometry.height);
 
2184
 
 
2185
        if (!toplevel->priv->expand) {
 
2186
                if (toplevel->priv->x_centered)
 
2187
                        x = (monitor_width - toplevel->priv->geometry.width) / 2;
 
2188
                if (toplevel->priv->y_centered)
 
2189
                        y = (monitor_height - toplevel->priv->geometry.height) / 2;
 
2190
        }
 
2191
 
 
2192
        w = h = -1;
 
2193
 
 
2194
        if (toplevel->priv->state == PANEL_STATE_NORMAL)
 
2195
                panel_toplevel_update_normal_position (toplevel, &x, &y, &w, &h);
 
2196
 
 
2197
        else if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN)
 
2198
                panel_toplevel_update_auto_hide_position (toplevel, &x, &y, &w, &h, FALSE);
 
2199
 
 
2200
        else 
 
2201
                panel_toplevel_update_hidden_position (toplevel, &x, &y, &w, &h);
 
2202
 
 
2203
        if (w != -1)
 
2204
                toplevel->priv->geometry.width = w;
 
2205
        if (h != -1)
 
2206
                toplevel->priv->geometry.height = h;
 
2207
 
 
2208
        /* This is some kind of snap: there's a possibility of an infinite loop
 
2209
         * because of the bevels of the frame that are set in
 
2210
         * panel_toplevel_update_edges(). The bevels change the width/height of
 
2211
         * the toplevel. The typical loop is:
 
2212
         * x = 1 => outer bevel => x = 0 => no outer bevel = > x = 1 => ...
 
2213
         * FIXME: maybe the real bug is that we enter into this loop (see bug
 
2214
         * #160748 to learn how to reproduce.) */
 
2215
        background = &toplevel->priv->panel_widget->background;
 
2216
        /* There's no bevels with a color/image background */
 
2217
        if (panel_background_effective_type (background) == PANEL_BACK_NONE) {
 
2218
                GtkStyleContext *context;
 
2219
                GtkStateFlags    state;
 
2220
                GdkRectangle    *geometry;
 
2221
                GtkBorder        padding;
 
2222
                int              max_size;
 
2223
 
 
2224
                state = gtk_widget_get_state_flags (GTK_WIDGET (toplevel->priv->inner_frame));
 
2225
                context = gtk_widget_get_style_context (GTK_WIDGET (toplevel->priv->inner_frame));
 
2226
                gtk_style_context_get_padding (context, state, &padding);
 
2227
                geometry = &toplevel->priv->geometry;
 
2228
 
 
2229
                if (x <= padding.left && x > 0 &&
 
2230
                    !toplevel->priv->x_centered)
 
2231
                        x = 0;
 
2232
 
 
2233
                if (y <= padding.top && y > 0 &&
 
2234
                    !toplevel->priv->y_centered)
 
2235
                        y = 0;
 
2236
 
 
2237
                max_size = monitor_width - geometry->width - padding.right;
 
2238
                if (x + padding.left >= max_size && x < max_size &&
 
2239
                    !toplevel->priv->x_centered)
 
2240
                        x = max_size;
 
2241
 
 
2242
                max_size = monitor_height - geometry->height - padding.bottom;
 
2243
                if (y + padding.top >= max_size && y < max_size &&
 
2244
                    !toplevel->priv->y_centered)
 
2245
                        y = max_size;
 
2246
        }
 
2247
 
 
2248
        x += panel_multiscreen_x (screen, toplevel->priv->monitor);
 
2249
        y += panel_multiscreen_y (screen, toplevel->priv->monitor);
 
2250
 
 
2251
        toplevel->priv->geometry.x = x;
 
2252
        toplevel->priv->geometry.y = y;
 
2253
}
 
2254
 
 
2255
static int
 
2256
calculate_minimum_height (GtkWidget        *widget,
 
2257
                          PanelOrientation  orientation)
 
2258
{
 
2259
        GtkStateFlags     state;
 
2260
        GtkStyleContext  *style_context;
 
2261
        const PangoFontDescription *font_desc;
 
2262
        PangoContext     *pango_context;
 
2263
        PangoFontMetrics *metrics;
 
2264
        GtkBorder         padding;
 
2265
        int               focus_width = 0;
 
2266
        int               focus_pad = 0;
 
2267
        int               ascent;
 
2268
        int               descent;
 
2269
        int               thickness;
 
2270
  
 
2271
        state = gtk_widget_get_state_flags (widget);
 
2272
        style_context = gtk_widget_get_style_context (widget);
 
2273
        gtk_style_context_get (style_context, state, "font", &font_desc, NULL);
 
2274
 
 
2275
        pango_context = gtk_widget_get_pango_context (widget);
 
2276
        metrics = pango_context_get_metrics (pango_context,
 
2277
                                             font_desc,
 
2278
                                             pango_context_get_language (pango_context));
 
2279
        ascent  = pango_font_metrics_get_ascent  (metrics);
 
2280
        descent = pango_font_metrics_get_descent (metrics);
 
2281
  
 
2282
        pango_font_metrics_unref (metrics);
 
2283
 
 
2284
        gtk_style_context_get_padding (style_context, state, &padding);
 
2285
        gtk_widget_style_get (widget,
 
2286
                              "focus-line-width", &focus_width,
 
2287
                              "focus-padding", &focus_pad,
 
2288
                              NULL);
 
2289
 
 
2290
        thickness = orientation & PANEL_HORIZONTAL_MASK ?
 
2291
                padding.top + padding.bottom :
 
2292
                padding.left + padding.right;
 
2293
 
 
2294
        return PANGO_PIXELS (ascent + descent) + 2 * (focus_width + focus_pad) + thickness;
 
2295
}
 
2296
 
 
2297
static int
 
2298
panel_toplevel_update_size_from_hints (PanelToplevel  *toplevel,
 
2299
                                       int             requisition_size,
 
2300
                                       int             monitor_size,
 
2301
                                       int             non_panel_widget_size)
 
2302
{
 
2303
        int                   nb_size_hints;
 
2304
        AppletSizeHints      *applets_hints;
 
2305
        AppletSizeHintsAlloc *using_hint;
 
2306
 
 
2307
        int i;
 
2308
        int total_size;
 
2309
        int full_hints;
 
2310
 
 
2311
        total_size = non_panel_widget_size + requisition_size;
 
2312
 
 
2313
        nb_size_hints = toplevel->priv->panel_widget->nb_applets_size_hints;
 
2314
        if (nb_size_hints <= 0)
 
2315
                return total_size;
 
2316
 
 
2317
        applets_hints = toplevel->priv->panel_widget->applets_hints;
 
2318
        using_hint = toplevel->priv->panel_widget->applets_using_hint;
 
2319
 
 
2320
        for (i = 0; i < nb_size_hints; i++) {
 
2321
                using_hint[i].index = applets_hints[i].len - 2;
 
2322
                using_hint[i].size = applets_hints[i].hints[applets_hints[i].len - 1];
 
2323
                total_size += using_hint[i].size;
 
2324
        }
 
2325
 
 
2326
        if (total_size > monitor_size)
 
2327
                return monitor_size;
 
2328
 
 
2329
        full_hints = 0;
 
2330
        while (full_hints != nb_size_hints && total_size < monitor_size) {
 
2331
                int bonus;
 
2332
                int extra_bonus;
 
2333
 
 
2334
                bonus = (monitor_size - total_size)
 
2335
                        / (nb_size_hints - full_hints);
 
2336
                extra_bonus = (monitor_size - total_size)
 
2337
                              % (nb_size_hints - full_hints);
 
2338
                full_hints = 0;
 
2339
 
 
2340
                for (i = 0; i < nb_size_hints; i++) {
 
2341
                        int new_size;
 
2342
                        int current_bonus;
 
2343
 
 
2344
                        current_bonus = bonus;
 
2345
 
 
2346
                        /* first find the (max, min) range in hints that we
 
2347
                         * will use; since we try to allocate as much size as
 
2348
                         * possible, this means we want the (max, min) range
 
2349
                         * where min is the highest possible (ie, the range
 
2350
                         * with the smaller index possible), while still
 
2351
                         * keeping min smaller than the potential new size */
 
2352
                        while (using_hint[i].index > 0 &&
 
2353
                               applets_hints[i].hints[using_hint[i].index - 1] < using_hint[i].size + current_bonus) {
 
2354
                                new_size = applets_hints[i].hints[using_hint[i].index - 1];
 
2355
                                current_bonus = using_hint[i].size
 
2356
                                                + current_bonus - new_size;
 
2357
                                total_size = total_size - using_hint[i].size
 
2358
                                             + new_size;
 
2359
 
 
2360
                                using_hint[i].index -= 2;
 
2361
                                using_hint[i].size = new_size;
 
2362
                        }
 
2363
 
 
2364
                        /* now, give the bonus, while still keeping a size that
 
2365
                         * is lower than max from the (max, min) range we've
 
2366
                         * settled for */
 
2367
                        new_size = MIN (applets_hints[i].hints[using_hint[i].index],
 
2368
                                        using_hint[i].size + current_bonus);
 
2369
                        if (new_size > using_hint[i].size) {
 
2370
                                total_size += (new_size - using_hint[i].size);
 
2371
                                using_hint[i].size = new_size;
 
2372
                        }
 
2373
 
 
2374
 
 
2375
                        /* if there's some extra bonus to take, try to allocate
 
2376
                         * it too */
 
2377
                        if (extra_bonus > 0) {
 
2378
                                new_size = MIN (applets_hints[i].hints[using_hint[i].index],
 
2379
                                                using_hint[i].size + extra_bonus);
 
2380
                                if (new_size > using_hint[i].size) {
 
2381
                                        total_size += (new_size
 
2382
                                                       - using_hint[i].size);
 
2383
                                        extra_bonus -= (new_size
 
2384
                                                        - using_hint[i].size);
 
2385
                                        using_hint[i].size = new_size;
 
2386
                                }
 
2387
                        }
 
2388
 
 
2389
                        if (using_hint[i].size == applets_hints[i].hints[using_hint[i].index])
 
2390
                                full_hints++;
 
2391
                }
 
2392
        }
 
2393
 
 
2394
        return total_size;
 
2395
}
 
2396
 
 
2397
static void
 
2398
panel_toplevel_update_size (PanelToplevel  *toplevel,
 
2399
                            GtkRequisition *requisition)
 
2400
{
 
2401
        GtkWidget       *widget;
 
2402
        GtkStyleContext *context;
 
2403
        GtkStateFlags    state;
 
2404
        GtkBorder        padding;
 
2405
        int              monitor_width, monitor_height;
 
2406
        int              width, height;
 
2407
        int              minimum_height;
 
2408
        int              non_panel_widget_size;
 
2409
 
 
2410
        if (toplevel->priv->animating)
 
2411
                return;
 
2412
 
 
2413
        widget = GTK_WIDGET (toplevel);
 
2414
        state = gtk_widget_get_state_flags (widget);
 
2415
        context = gtk_widget_get_style_context (widget);
 
2416
        gtk_style_context_get_padding (context, state, &padding);
 
2417
 
 
2418
        panel_toplevel_get_monitor_geometry (
 
2419
                        toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
2420
 
 
2421
        width  = requisition->width;
 
2422
        height = requisition->height;
 
2423
 
 
2424
        if (!toplevel->priv->expand &&
 
2425
            !toplevel->priv->buttons_enabled)
 
2426
                non_panel_widget_size = 2 * HANDLE_SIZE;
 
2427
        else
 
2428
                non_panel_widget_size = 0;
 
2429
 
 
2430
        minimum_height = calculate_minimum_height (GTK_WIDGET (toplevel),
 
2431
                                                   toplevel->priv->orientation);
 
2432
 
 
2433
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 
2434
 
 
2435
                height = MAX (MIN (MAX (height, toplevel->priv->size),
 
2436
                                   panel_toplevel_get_maximum_size (toplevel)),
 
2437
                              minimum_height);
 
2438
 
 
2439
                if (toplevel->priv->expand)
 
2440
                        width  = monitor_width;
 
2441
                else
 
2442
                        width = panel_toplevel_update_size_from_hints (
 
2443
                                                        toplevel,
 
2444
                                                        requisition->width,
 
2445
                                                        monitor_width,
 
2446
                                                        non_panel_widget_size);
 
2447
 
 
2448
                width  = MAX (MINIMUM_WIDTH, width);
 
2449
        } else {
 
2450
                width = MAX (MIN (MAX (width, toplevel->priv->size),
 
2451
                                  panel_toplevel_get_maximum_size (toplevel)),
 
2452
                             minimum_height);
 
2453
 
 
2454
                if (toplevel->priv->expand)
 
2455
                        height = monitor_height;
 
2456
                else
 
2457
                        height = panel_toplevel_update_size_from_hints (
 
2458
                                                        toplevel,
 
2459
                                                        requisition->height,
 
2460
                                                        monitor_height,
 
2461
                                                        non_panel_widget_size);
 
2462
 
 
2463
                height = MAX (MINIMUM_WIDTH, height);
 
2464
        }
 
2465
 
 
2466
        if (toplevel->priv->edges & PANEL_EDGE_TOP)
 
2467
                height += padding.top;
 
2468
        if (toplevel->priv->edges & PANEL_EDGE_BOTTOM)
 
2469
                height += padding.bottom;
 
2470
        if (toplevel->priv->edges & PANEL_EDGE_LEFT)
 
2471
                width += padding.left;
 
2472
        if (toplevel->priv->edges & PANEL_EDGE_RIGHT)
 
2473
                width += padding.right;
 
2474
 
 
2475
        toplevel->priv->geometry.width  = CLAMP (width,  0, monitor_width);
 
2476
        toplevel->priv->geometry.height = CLAMP (height, 0, monitor_height);
 
2477
        toplevel->priv->original_width  = toplevel->priv->geometry.width;
 
2478
        toplevel->priv->original_height = toplevel->priv->geometry.height;
 
2479
}
 
2480
 
 
2481
static void
 
2482
panel_toplevel_update_geometry (PanelToplevel  *toplevel,
 
2483
                                GtkRequisition *requisition)
 
2484
{
 
2485
        toplevel->priv->updated_geometry_initial = TRUE;
 
2486
        panel_toplevel_update_size (toplevel, requisition);
 
2487
        panel_toplevel_update_position (toplevel);
 
2488
 
 
2489
        panel_toplevel_update_struts (toplevel, FALSE);
 
2490
 
 
2491
        if (toplevel->priv->state == PANEL_STATE_NORMAL ||
 
2492
            toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) {
 
2493
                panel_struts_update_toplevel_geometry (toplevel,
 
2494
                                                       &toplevel->priv->geometry.x,
 
2495
                                                       &toplevel->priv->geometry.y,
 
2496
                                                       &toplevel->priv->geometry.width,
 
2497
                                                       &toplevel->priv->geometry.height);
 
2498
        } else {
 
2499
                panel_struts_update_toplevel_geometry (toplevel,
 
2500
                                                       &toplevel->priv->geometry.x,
 
2501
                                                       &toplevel->priv->geometry.y,
 
2502
                                                       NULL, NULL);
 
2503
        }
 
2504
 
 
2505
        panel_toplevel_update_edges (toplevel);
 
2506
        panel_toplevel_update_description (toplevel);
 
2507
}
 
2508
 
 
2509
static gboolean
 
2510
panel_toplevel_popup_panel_menu (PanelToplevel *toplevel)
 
2511
{
 
2512
        gboolean retval = FALSE;
 
2513
 
 
2514
        g_signal_emit_by_name (toplevel, "popup_menu", &retval);
 
2515
 
 
2516
        return retval;
 
2517
}
 
2518
 
 
2519
static gboolean
 
2520
panel_toplevel_toggle_expand (PanelToplevel *toplevel)
 
2521
{
 
2522
        panel_toplevel_set_expand (toplevel, !toplevel->priv->expand);
 
2523
 
 
2524
        return TRUE;
 
2525
}
 
2526
 
 
2527
static gboolean
 
2528
panel_toplevel_expand (PanelToplevel *toplevel)
 
2529
{
 
2530
        panel_toplevel_set_expand (toplevel, TRUE);
 
2531
 
 
2532
        return TRUE;
 
2533
}
 
2534
 
 
2535
static gboolean
 
2536
panel_toplevel_unexpand (PanelToplevel *toplevel)
 
2537
{
 
2538
        panel_toplevel_set_expand (toplevel, FALSE);
 
2539
 
 
2540
        return TRUE;
 
2541
}
 
2542
 
 
2543
static gboolean
 
2544
panel_toplevel_toggle_hidden (PanelToplevel *toplevel)
 
2545
{
 
2546
        if (toplevel->priv->state == PANEL_STATE_NORMAL)
 
2547
                panel_toplevel_hide (toplevel, toplevel->priv->auto_hide, -1);
 
2548
        else
 
2549
                panel_toplevel_unhide (toplevel);
 
2550
 
 
2551
        return FALSE;
 
2552
}
 
2553
 
 
2554
static gboolean
 
2555
panel_toplevel_begin_move (PanelToplevel *toplevel)
 
2556
{
 
2557
        if (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE)
 
2558
                return FALSE;
 
2559
 
 
2560
        panel_toplevel_begin_grab_op (
 
2561
                        toplevel, PANEL_GRAB_OP_MOVE, TRUE, GDK_CURRENT_TIME);
 
2562
 
 
2563
        return TRUE;
 
2564
}
 
2565
 
 
2566
static gboolean
 
2567
panel_toplevel_begin_resize (PanelToplevel *toplevel)
 
2568
{
 
2569
        if (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE)
 
2570
                return FALSE;
 
2571
 
 
2572
        panel_toplevel_begin_grab_op (
 
2573
                        toplevel, PANEL_GRAB_OP_RESIZE, TRUE, GDK_CURRENT_TIME);
 
2574
 
 
2575
        return TRUE;
 
2576
}
 
2577
 
 
2578
static void
 
2579
panel_toplevel_move_resize_window (PanelToplevel *toplevel,
 
2580
                                   gboolean       move,
 
2581
                                   gboolean       resize)
 
2582
{
 
2583
        GtkWidget *widget;
 
2584
 
 
2585
        widget = GTK_WIDGET (toplevel);
 
2586
 
 
2587
        g_assert (gtk_widget_get_realized (widget));
 
2588
 
 
2589
        if (move && resize)
 
2590
                gdk_window_move_resize (gtk_widget_get_window (widget),
 
2591
                                        toplevel->priv->geometry.x,
 
2592
                                        toplevel->priv->geometry.y,
 
2593
                                        toplevel->priv->geometry.width,
 
2594
                                        toplevel->priv->geometry.height);
 
2595
        else if (move)
 
2596
                gdk_window_move (gtk_widget_get_window (widget),
 
2597
                                 toplevel->priv->geometry.x,
 
2598
                                 toplevel->priv->geometry.y);
 
2599
        else if (resize)
 
2600
                gdk_window_resize (gtk_widget_get_window (widget),
 
2601
                                   toplevel->priv->geometry.width,
 
2602
                                   toplevel->priv->geometry.height);
 
2603
}
 
2604
 
 
2605
static void
 
2606
panel_toplevel_initially_hide (PanelToplevel *toplevel)
 
2607
{
 
2608
        toplevel->priv->initial_animation_done = FALSE;
 
2609
 
 
2610
        /* We start the panel off hidden until all the applets are
 
2611
         * loaded, and then finally slide it down when it's ready to be
 
2612
         * used */
 
2613
        toplevel->priv->state = PANEL_STATE_AUTO_HIDDEN;
 
2614
        gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
2615
}
 
2616
 
 
2617
static void
 
2618
panel_toplevel_realize (GtkWidget *widget)
 
2619
{
 
2620
        PanelToplevel *toplevel = (PanelToplevel *) widget;
 
2621
        GdkWindow     *window;
 
2622
 
 
2623
        gtk_window_set_decorated (GTK_WINDOW (widget), FALSE);
 
2624
        gtk_window_stick (GTK_WINDOW (widget));
 
2625
 
 
2626
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->realize)
 
2627
                GTK_WIDGET_CLASS (panel_toplevel_parent_class)->realize (widget);
 
2628
 
 
2629
        window = gtk_widget_get_window (widget);
 
2630
 
 
2631
        panel_struts_set_window_hint (toplevel);
 
2632
        panel_xutils_set_window_type (window, PANEL_XUTILS_TYPE_DOCK);
 
2633
 
 
2634
        gdk_window_set_group (window, window);
 
2635
        gdk_window_set_geometry_hints (window, NULL, GDK_HINT_POS);
 
2636
 
 
2637
        panel_toplevel_initially_hide (toplevel);
 
2638
 
 
2639
        panel_toplevel_move_resize_window (toplevel, TRUE, TRUE);
 
2640
}
 
2641
 
 
2642
static void
 
2643
panel_toplevel_disconnect_timeouts (PanelToplevel *toplevel)
 
2644
{
 
2645
        if (toplevel->priv->hide_timeout)
 
2646
                g_source_remove (toplevel->priv->hide_timeout);
 
2647
        toplevel->priv->hide_timeout = 0;
 
2648
 
 
2649
        if (toplevel->priv->unhide_timeout)
 
2650
                g_source_remove (toplevel->priv->unhide_timeout);
 
2651
        toplevel->priv->unhide_timeout = 0;
 
2652
 
 
2653
        if (toplevel->priv->animation_timeout)
 
2654
                g_source_remove (toplevel->priv->animation_timeout);
 
2655
        toplevel->priv->animation_timeout = 0;
 
2656
}
 
2657
 
 
2658
static void
 
2659
panel_toplevel_unrealize (GtkWidget *widget)
 
2660
{
 
2661
        panel_toplevel_disconnect_timeouts (PANEL_TOPLEVEL (widget));
 
2662
 
 
2663
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->unrealize)
 
2664
                GTK_WIDGET_CLASS (panel_toplevel_parent_class)->unrealize (widget);
 
2665
}
 
2666
 
 
2667
static void
 
2668
panel_toplevel_dispose (GObject *widget)
 
2669
{
 
2670
        PanelToplevel *toplevel = (PanelToplevel *) widget;
 
2671
        
 
2672
        panel_toplevel_disconnect_timeouts (toplevel);
 
2673
 
 
2674
        G_OBJECT_CLASS (panel_toplevel_parent_class)->dispose (widget);
 
2675
}
 
2676
 
 
2677
static void
 
2678
panel_toplevel_check_resize (GtkContainer *container)
 
2679
{
 
2680
        GtkAllocation   allocation;
 
2681
        GtkRequisition  requisition;
 
2682
        GtkWidget      *widget;
 
2683
 
 
2684
        widget = GTK_WIDGET (container);
 
2685
 
 
2686
        if (!gtk_widget_get_visible (widget))
 
2687
                return;
 
2688
 
 
2689
        gtk_widget_get_preferred_size (widget, &requisition, NULL);
 
2690
        gtk_widget_get_allocation (widget, &allocation);
 
2691
 
 
2692
        allocation.width = requisition.width;
 
2693
        allocation.height = requisition.height;
 
2694
 
 
2695
        gtk_widget_size_allocate (widget, &allocation);
 
2696
}
 
2697
 
 
2698
static void
 
2699
panel_toplevel_size_request (GtkWidget      *widget,
 
2700
                             GtkRequisition *requisition)
 
2701
{
 
2702
        PanelToplevel *toplevel;
 
2703
        GtkBin        *bin;
 
2704
        GtkWidget     *child;
 
2705
        GdkRectangle   old_geometry;
 
2706
        int            position_changed = FALSE;
 
2707
        int            size_changed = FALSE;
 
2708
        int            dummy; /* to pass a valid pointer */
 
2709
 
 
2710
        toplevel = PANEL_TOPLEVEL (widget);
 
2711
        bin = GTK_BIN (widget);
 
2712
 
 
2713
        /* we get a size request when there are new monitors, so first try to
 
2714
         * see if we need to move to a new monitor */
 
2715
        panel_toplevel_update_monitor (toplevel);
 
2716
 
 
2717
        child = gtk_bin_get_child (bin);
 
2718
        if (child && gtk_widget_get_visible (child)) {
 
2719
                gtk_widget_get_preferred_width (child, &dummy, &requisition->width);
 
2720
                gtk_widget_get_preferred_height (child, &dummy, &requisition->height);
 
2721
        }
 
2722
 
 
2723
        old_geometry = toplevel->priv->geometry;
 
2724
 
 
2725
        panel_toplevel_update_geometry (toplevel, requisition);
 
2726
 
 
2727
        requisition->width  = toplevel->priv->geometry.width;
 
2728
        requisition->height = toplevel->priv->geometry.height;
 
2729
 
 
2730
        if (!gtk_widget_get_realized (widget))
 
2731
                return;
 
2732
 
 
2733
        if (old_geometry.width  != toplevel->priv->geometry.width ||
 
2734
            old_geometry.height != toplevel->priv->geometry.height)
 
2735
                size_changed = TRUE;
 
2736
 
 
2737
        if (old_geometry.x != toplevel->priv->geometry.x ||
 
2738
            old_geometry.y != toplevel->priv->geometry.y)
 
2739
                position_changed = TRUE;
 
2740
 
 
2741
        panel_toplevel_move_resize_window (toplevel, position_changed, size_changed);
 
2742
}
 
2743
 
 
2744
static void
 
2745
panel_toplevel_get_preferred_width(GtkWidget *widget, gint *minimal_width, gint *natural_width)
 
2746
{
 
2747
        GtkRequisition requisition;
 
2748
 
 
2749
        panel_toplevel_size_request (widget, &requisition);
 
2750
 
 
2751
        *minimal_width = *natural_width = requisition.width;
 
2752
}
 
2753
 
 
2754
static void
 
2755
panel_toplevel_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height)
 
2756
{
 
2757
        GtkRequisition requisition;
 
2758
 
 
2759
        panel_toplevel_size_request (widget, &requisition);
 
2760
 
 
2761
        *minimal_height = *natural_height = requisition.height;
 
2762
}
 
2763
 
 
2764
static void
 
2765
panel_toplevel_size_allocate (GtkWidget     *widget,
 
2766
                              GtkAllocation *allocation)
 
2767
{
 
2768
        PanelToplevel   *toplevel = (PanelToplevel *) widget;
 
2769
        GtkBin          *bin = (GtkBin *) widget;
 
2770
        GtkStyleContext *context;
 
2771
        GtkStateFlags    state;
 
2772
        GtkBorder        padding;
 
2773
        GtkWidget       *child;
 
2774
        GtkAllocation    challoc;
 
2775
        GtkAllocation    child_allocation;
 
2776
 
 
2777
        gtk_widget_set_allocation (widget, allocation);
 
2778
 
 
2779
        if (toplevel->priv->expand ||
 
2780
            toplevel->priv->buttons_enabled)
 
2781
                challoc = *allocation;
 
2782
        else {
 
2783
                if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 
2784
                        challoc.x      = HANDLE_SIZE;
 
2785
                        challoc.y      = 0;
 
2786
                        challoc.width  = allocation->width - 2 * HANDLE_SIZE;
 
2787
                        challoc.height = allocation->height;
 
2788
                } else {
 
2789
                        challoc.x      = 0;
 
2790
                        challoc.y      = HANDLE_SIZE;
 
2791
                        challoc.width  = allocation->width;
 
2792
                        challoc.height = allocation->height - 2 * HANDLE_SIZE;
 
2793
                }
 
2794
        }
 
2795
 
 
2796
        state = gtk_widget_get_state_flags (widget);
 
2797
        context = gtk_widget_get_style_context (widget);
 
2798
        gtk_style_context_get_padding (context, state, &padding);
 
2799
 
 
2800
        if (toplevel->priv->edges & PANEL_EDGE_TOP) {
 
2801
                challoc.y += padding.top;
 
2802
                challoc.height -= padding.top;
 
2803
        }
 
2804
 
 
2805
        if (toplevel->priv->edges & PANEL_EDGE_LEFT) {
 
2806
                challoc.x += padding.left;
 
2807
                challoc.width -= padding.left;
 
2808
        }
 
2809
 
 
2810
        if (toplevel->priv->edges & PANEL_EDGE_BOTTOM)
 
2811
                challoc.height -= padding.bottom;
 
2812
 
 
2813
        if (toplevel->priv->edges & PANEL_EDGE_RIGHT)
 
2814
                challoc.width -= padding.right;
 
2815
 
 
2816
        challoc.width  = MAX (1, challoc.width);
 
2817
        challoc.height = MAX (1, challoc.height);
 
2818
 
 
2819
        child = gtk_bin_get_child (bin);
 
2820
        gtk_widget_get_allocation (child, &child_allocation);
 
2821
 
 
2822
        if (gtk_widget_get_mapped (widget) &&
 
2823
            (challoc.x != child_allocation.x ||
 
2824
             challoc.y != child_allocation.y ||
 
2825
             challoc.width  != child_allocation.width ||
 
2826
             challoc.height != child_allocation.height)) {
 
2827
                GtkAllocation allocation;
 
2828
 
 
2829
                gtk_widget_get_allocation (widget, &allocation);
 
2830
                gdk_window_invalidate_rect (gtk_widget_get_window (widget), &allocation, FALSE);
 
2831
        }
 
2832
 
 
2833
        if (child && gtk_widget_get_visible (child))
 
2834
                gtk_widget_size_allocate (child, &challoc);
 
2835
}
 
2836
 
 
2837
static gboolean
 
2838
panel_toplevel_draw (GtkWidget *widget,
 
2839
                     cairo_t   *cr)
 
2840
{
 
2841
        PanelToplevel   *toplevel = (PanelToplevel *) widget;
 
2842
        PanelFrameEdge   edges;
 
2843
        gboolean         retval = FALSE;
 
2844
        GtkStyleContext *context;
 
2845
        GtkStateFlags    state;
 
2846
        GtkBorder        padding;
 
2847
        int awidth, aheight;
 
2848
 
 
2849
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->draw)
 
2850
                retval = GTK_WIDGET_CLASS (panel_toplevel_parent_class)->draw (widget, cr);
 
2851
 
 
2852
        edges = toplevel->priv->edges;
 
2853
        /* FIXMEchpe: WTF!? */
 
2854
        panel_frame_draw (widget, cr, edges);
 
2855
 
 
2856
        if (toplevel->priv->expand ||
 
2857
            toplevel->priv->buttons_enabled)
 
2858
                return retval;
 
2859
 
 
2860
        state = gtk_widget_get_state_flags (widget);
 
2861
        awidth = gtk_widget_get_allocated_width (widget);
 
2862
        aheight = gtk_widget_get_allocated_height (widget);
 
2863
 
 
2864
        context = gtk_widget_get_style_context (widget);
 
2865
        gtk_style_context_get_padding (context, state, &padding);
 
2866
 
 
2867
        gtk_style_context_save (context);
 
2868
        gtk_style_context_set_state (context, state);
 
2869
 
 
2870
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 
2871
                int x, y, width, height;
 
2872
 
 
2873
                x      = 0;
 
2874
                y      = 0;
 
2875
                width  = HANDLE_SIZE;
 
2876
                height = aheight;
 
2877
 
 
2878
                if (edges & PANEL_EDGE_TOP) {
 
2879
                        y += padding.top;
 
2880
                        height -= padding.top;
 
2881
                }
 
2882
                if (edges & PANEL_EDGE_BOTTOM)
 
2883
                        height -= padding.bottom;
 
2884
                if (edges & PANEL_EDGE_LEFT)
 
2885
                        x += padding.left;
 
2886
 
 
2887
                cairo_save (cr);
 
2888
                gtk_render_handle (context, cr, x, y, width, height);
 
2889
                cairo_restore (cr);
 
2890
 
 
2891
                x = awidth - HANDLE_SIZE;
 
2892
                if (edges & PANEL_EDGE_RIGHT)
 
2893
                        x -= padding.right;
 
2894
 
 
2895
                cairo_save (cr);
 
2896
                gtk_render_handle (context, cr, x, y, width, height);
 
2897
                cairo_restore (cr);
 
2898
        } else {
 
2899
                int x, y, width, height;
 
2900
 
 
2901
                x      = 0;
 
2902
                y      = 0;
 
2903
                width  = awidth;
 
2904
                height = HANDLE_SIZE;
 
2905
 
 
2906
                if (edges & PANEL_EDGE_LEFT) {
 
2907
                        x += padding.left;
 
2908
                        width -= padding.left;
 
2909
                }
 
2910
                if (edges & PANEL_EDGE_RIGHT)
 
2911
                        width -= padding.right;
 
2912
                if (edges & PANEL_EDGE_TOP)
 
2913
                        y += padding.top;
 
2914
 
 
2915
                cairo_save (cr);
 
2916
                gtk_render_handle (context, cr, x, y, width, height);
 
2917
                cairo_restore (cr);
 
2918
 
 
2919
                y = aheight - HANDLE_SIZE;
 
2920
                if (edges & PANEL_EDGE_BOTTOM)
 
2921
                        y -= padding.bottom;
 
2922
 
 
2923
                cairo_save (cr);
 
2924
                gtk_render_handle (context, cr, x, y, width, height);
 
2925
                cairo_restore (cr);
 
2926
        }
 
2927
 
 
2928
        gtk_style_context_restore (context);
 
2929
 
 
2930
        return retval;
 
2931
}
 
2932
 
 
2933
static gboolean
 
2934
panel_toplevel_button_press_event (GtkWidget      *widget,
 
2935
                                   GdkEventButton *event)
 
2936
{
 
2937
        PanelToplevel *toplevel;
 
2938
        guint          modifiers;
 
2939
        GtkWidget     *event_widget;
 
2940
 
 
2941
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE);
 
2942
 
 
2943
        toplevel = PANEL_TOPLEVEL (widget);
 
2944
 
 
2945
        if (event->button != 1 && event->button != 2)
 
2946
                return FALSE;
 
2947
 
 
2948
        if (toplevel->priv->animating)
 
2949
                return FALSE;
 
2950
 
 
2951
        modifiers = event->state & gtk_accelerator_get_default_mod_mask ();
 
2952
 
 
2953
        /* Get the mouse-button modifier from metacity so that only intentional
 
2954
         * moves are considered. We don't this for non-expanded panels since we
 
2955
         * only have the handles that the user can grab. */
 
2956
        if (toplevel->priv->expand &&
 
2957
            modifiers != panel_bindings_get_mouse_button_modifier_keymask ())
 
2958
                return FALSE;
 
2959
 
 
2960
        gdk_window_get_user_data (event->window, (gpointer)&event_widget);
 
2961
        g_assert (GTK_IS_WIDGET (event_widget));
 
2962
        gtk_widget_translate_coordinates (event_widget,
 
2963
                                          widget,
 
2964
                                          event->x,
 
2965
                                          event->y,
 
2966
                                          &toplevel->priv->drag_offset_x,
 
2967
                                          &toplevel->priv->drag_offset_y);
 
2968
 
 
2969
        panel_toplevel_begin_grab_op (toplevel, PANEL_GRAB_OP_MOVE, FALSE, event->time);
 
2970
 
 
2971
        return TRUE;
 
2972
}
 
2973
 
 
2974
static gboolean
 
2975
panel_toplevel_button_release_event (GtkWidget      *widget,
 
2976
                                     GdkEventButton *event)
 
2977
{
 
2978
        PanelToplevel *toplevel;
 
2979
 
 
2980
        if (event->button != 1 && event->button != 2)
 
2981
                return FALSE;
 
2982
 
 
2983
        toplevel = PANEL_TOPLEVEL (widget);
 
2984
 
 
2985
        if (toplevel->priv->grab_op == PANEL_GRAB_OP_NONE)
 
2986
                return FALSE;
 
2987
 
 
2988
        if (toplevel->priv->grab_is_keyboard)
 
2989
                return FALSE;
 
2990
 
 
2991
        panel_toplevel_end_grab_op (toplevel, event->time);
 
2992
 
 
2993
        return TRUE;
 
2994
}
 
2995
 
 
2996
static gboolean
 
2997
panel_toplevel_key_press_event (GtkWidget   *widget,
 
2998
                                GdkEventKey *event)
 
2999
{
 
3000
        PanelToplevel *toplevel = (PanelToplevel *) widget;
 
3001
 
 
3002
        if (toplevel->priv->grab_op != PANEL_GRAB_OP_NONE &&
 
3003
            panel_toplevel_handle_grab_op_key_event (toplevel, event))
 
3004
                return TRUE;
 
3005
 
 
3006
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->key_press_event)
 
3007
                return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->key_press_event (widget, event);
 
3008
 
 
3009
        return FALSE;
 
3010
}
 
3011
 
 
3012
static gboolean
 
3013
panel_toplevel_motion_notify_event (GtkWidget      *widget,
 
3014
                                    GdkEventMotion *event)
 
3015
{
 
3016
        if (gdk_event_get_screen ((GdkEvent *)event) == 
 
3017
            gtk_window_get_screen (GTK_WINDOW (widget)))
 
3018
                return panel_toplevel_handle_grab_op_motion_event (
 
3019
                                PANEL_TOPLEVEL (widget), event);
 
3020
        else
 
3021
                return FALSE;
 
3022
}
 
3023
 
 
3024
static gboolean
 
3025
panel_toplevel_animation_timeout (PanelToplevel *toplevel)
 
3026
{
 
3027
        gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
3028
 
 
3029
        if (!toplevel->priv->animating) {
 
3030
                toplevel->priv->animation_end_x              = 0xdead;
 
3031
                toplevel->priv->animation_end_y              = 0xdead;
 
3032
                toplevel->priv->animation_end_width          = 0xdead;
 
3033
                toplevel->priv->animation_end_height         = 0xdead;
 
3034
                toplevel->priv->animation_start_time.tv_sec  = 0xdead;
 
3035
                toplevel->priv->animation_start_time.tv_usec = 0xdead;
 
3036
                toplevel->priv->animation_end_time.tv_sec    = 0xdead;
 
3037
                toplevel->priv->animation_end_time.tv_usec   = 0xdead;
 
3038
                toplevel->priv->animation_timeout            = 0;
 
3039
                toplevel->priv->initial_animation_done       = TRUE;
 
3040
        }
 
3041
 
 
3042
        return toplevel->priv->animating;
 
3043
}
 
3044
 
 
3045
static long
 
3046
panel_toplevel_get_animation_time (PanelToplevel *toplevel)
 
3047
{
 
3048
 /* The number of seconds to complete the animation.
 
3049
  */
 
3050
#define ANIMATION_TIME_FAST   0.4
 
3051
#define ANIMATION_TIME_MEDIUM 1.2
 
3052
#define ANIMATION_TIME_SLOW   2.0
 
3053
 
 
3054
        long t;
 
3055
 
 
3056
        switch (toplevel->priv->animation_speed) {
 
3057
        case PANEL_ANIMATION_SLOW:
 
3058
                t = ANIMATION_TIME_SLOW * G_USEC_PER_SEC;
 
3059
                break;
 
3060
        case PANEL_ANIMATION_MEDIUM:
 
3061
                t = ANIMATION_TIME_MEDIUM * G_USEC_PER_SEC;
 
3062
                break;
 
3063
        case PANEL_ANIMATION_FAST:
 
3064
                t = ANIMATION_TIME_FAST * G_USEC_PER_SEC;
 
3065
                break;
 
3066
        default:
 
3067
                g_assert_not_reached ();
 
3068
                break;
 
3069
        }
 
3070
 
 
3071
        return t;
 
3072
 
 
3073
#undef ANIMATION_TIME_FAST
 
3074
#undef ANIMATION_TIME_MEDIUM
 
3075
#undef ANIMATION_TIME_SLOW
 
3076
}
 
3077
 
 
3078
static void
 
3079
panel_toplevel_calculate_animation_end_geometry (PanelToplevel *toplevel)
 
3080
{
 
3081
        int        monitor_width, monitor_height;
 
3082
 
 
3083
        toplevel->priv->animation_end_x      = toplevel->priv->x;
 
3084
        toplevel->priv->animation_end_y      = toplevel->priv->y;
 
3085
        toplevel->priv->animation_end_width  = -1;
 
3086
        toplevel->priv->animation_end_height = -1;
 
3087
 
 
3088
        panel_toplevel_get_monitor_geometry (
 
3089
                                toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
3090
 
 
3091
        if (!toplevel->priv->expand) {
 
3092
 
 
3093
                if (toplevel->priv->x_centered)
 
3094
                        toplevel->priv->animation_end_x =
 
3095
                                (monitor_width - toplevel->priv->geometry.width) / 2;
 
3096
                if (toplevel->priv->y_centered)
 
3097
                        toplevel->priv->animation_end_y =
 
3098
                                (monitor_height - toplevel->priv->geometry.height) / 2;
 
3099
        }
 
3100
 
 
3101
        /* we consider the toplevels which are in the initial animation stage
 
3102
         * as in a normal state */
 
3103
        if (toplevel->priv->state == PANEL_STATE_NORMAL ||
 
3104
            (!toplevel->priv->initial_animation_done &&
 
3105
             !toplevel->priv->auto_hide))
 
3106
                panel_toplevel_update_normal_position (toplevel,
 
3107
                                                       &toplevel->priv->animation_end_x,
 
3108
                                                       &toplevel->priv->animation_end_y,
 
3109
                                                       &toplevel->priv->animation_end_width,
 
3110
                                                       &toplevel->priv->animation_end_height);
 
3111
 
 
3112
        else if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN)
 
3113
                panel_toplevel_update_auto_hide_position (toplevel,
 
3114
                                                          &toplevel->priv->animation_end_x,
 
3115
                                                          &toplevel->priv->animation_end_y,
 
3116
                                                          &toplevel->priv->animation_end_width,
 
3117
                                                          &toplevel->priv->animation_end_height,
 
3118
                                                          TRUE);
 
3119
        else
 
3120
                panel_toplevel_update_hidden_position (toplevel,
 
3121
                                                       &toplevel->priv->animation_end_x,
 
3122
                                                       &toplevel->priv->animation_end_y,
 
3123
                                                       &toplevel->priv->animation_end_width,
 
3124
                                                       &toplevel->priv->animation_end_height);
 
3125
}
 
3126
 
 
3127
static void
 
3128
panel_toplevel_start_animation (PanelToplevel *toplevel)
 
3129
{
 
3130
        GdkScreen      *screen;
 
3131
        GtkRequisition  requisition;
 
3132
        int             deltax, deltay, deltaw = 0, deltah = 0;
 
3133
        int             cur_x = -1, cur_y = -1;
 
3134
        long            t;
 
3135
 
 
3136
        panel_toplevel_calculate_animation_end_geometry (toplevel);
 
3137
 
 
3138
        toplevel->priv->animating = TRUE;
 
3139
 
 
3140
        panel_toplevel_update_struts (toplevel, TRUE);
 
3141
        panel_struts_update_toplevel_geometry (toplevel,
 
3142
                                               &toplevel->priv->animation_end_x,
 
3143
                                               &toplevel->priv->animation_end_y,
 
3144
                                               &toplevel->priv->animation_end_width,
 
3145
                                               &toplevel->priv->animation_end_height);
 
3146
        panel_toplevel_update_struts (toplevel, FALSE);
 
3147
 
 
3148
        gdk_window_get_origin (gtk_widget_get_window (GTK_WIDGET (toplevel)), &cur_x, &cur_y);
 
3149
 
 
3150
        screen = gtk_widget_get_screen (GTK_WIDGET (toplevel));
 
3151
 
 
3152
        cur_x -= panel_multiscreen_x (screen, toplevel->priv->monitor);
 
3153
        cur_y -= panel_multiscreen_y (screen, toplevel->priv->monitor);
 
3154
 
 
3155
        deltax = toplevel->priv->animation_end_x - cur_x;
 
3156
        deltay = toplevel->priv->animation_end_y - cur_y;
 
3157
 
 
3158
        gtk_widget_get_requisition (GTK_WIDGET (toplevel), &requisition);
 
3159
 
 
3160
        if (toplevel->priv->animation_end_width != -1)
 
3161
                deltaw = toplevel->priv->animation_end_width - requisition.width;
 
3162
 
 
3163
        if (toplevel->priv->animation_end_height != -1)
 
3164
                deltah = toplevel->priv->animation_end_height - requisition.height;
 
3165
 
 
3166
        if (deltax == 0 && deltay == 0 && deltaw == 0 && deltah == 0) {
 
3167
                toplevel->priv->animation_end_x      = -1;
 
3168
                toplevel->priv->animation_end_y      = -1;
 
3169
                toplevel->priv->animation_end_width  = -1;
 
3170
                toplevel->priv->animation_end_height = -1;
 
3171
                toplevel->priv->animating            = FALSE;
 
3172
                return;
 
3173
        }
 
3174
 
 
3175
        g_get_current_time (&toplevel->priv->animation_start_time);
 
3176
 
 
3177
        t = panel_toplevel_get_animation_time (toplevel);
 
3178
        g_get_current_time (&toplevel->priv->animation_end_time);
 
3179
        g_time_val_add (&toplevel->priv->animation_end_time, t);
 
3180
 
 
3181
        if (!toplevel->priv->animation_timeout)
 
3182
                toplevel->priv->animation_timeout =
 
3183
                        g_timeout_add (20, (GSourceFunc) panel_toplevel_animation_timeout, toplevel);
 
3184
}
 
3185
 
 
3186
void
 
3187
panel_toplevel_hide (PanelToplevel    *toplevel,
 
3188
                     gboolean          auto_hide,
 
3189
                     GtkDirectionType  direction)
 
3190
{
 
3191
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
3192
 
 
3193
        if (toplevel->priv->state != PANEL_STATE_NORMAL)
 
3194
                return;
 
3195
 
 
3196
        g_signal_emit (toplevel, toplevel_signals [HIDE_SIGNAL], 0);
 
3197
 
 
3198
        if (auto_hide)
 
3199
                toplevel->priv->state = PANEL_STATE_AUTO_HIDDEN;
 
3200
        else {
 
3201
                if (direction == -1) {
 
3202
                        if (toplevel->priv->orientation & PANEL_VERTICAL_MASK)
 
3203
                                direction = GTK_DIR_UP;
 
3204
                        else
 
3205
                                direction = GTK_DIR_LEFT;
 
3206
                }
 
3207
 
 
3208
                switch (direction) {
 
3209
                case GTK_DIR_UP:
 
3210
                        g_return_if_fail (toplevel->priv->orientation & PANEL_VERTICAL_MASK);
 
3211
                        toplevel->priv->state = PANEL_STATE_HIDDEN_UP;
 
3212
                        break;
 
3213
                case GTK_DIR_DOWN:
 
3214
                        g_return_if_fail (toplevel->priv->orientation & PANEL_VERTICAL_MASK);
 
3215
                        toplevel->priv->state = PANEL_STATE_HIDDEN_DOWN;
 
3216
                        break;
 
3217
                case GTK_DIR_LEFT:
 
3218
                        g_return_if_fail (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK);
 
3219
                        toplevel->priv->state = PANEL_STATE_HIDDEN_LEFT;
 
3220
                        break;
 
3221
                case GTK_DIR_RIGHT:
 
3222
                        g_return_if_fail (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK);
 
3223
                        toplevel->priv->state = PANEL_STATE_HIDDEN_RIGHT;
 
3224
                        break;
 
3225
                default:
 
3226
                        g_assert_not_reached ();
 
3227
                        break;
 
3228
                }
 
3229
 
 
3230
                panel_toplevel_update_hide_buttons (toplevel);
 
3231
        }
 
3232
 
 
3233
        if (toplevel->priv->animate && gtk_widget_get_realized (GTK_WIDGET (toplevel)))
 
3234
                panel_toplevel_start_animation (toplevel);
 
3235
 
 
3236
        gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
3237
}
 
3238
 
 
3239
static gboolean
 
3240
panel_toplevel_auto_hide_timeout_handler (PanelToplevel *toplevel)
 
3241
{
 
3242
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
3243
 
 
3244
        if (panel_toplevel_get_autohide_disabled (toplevel)) {
 
3245
                toplevel->priv->hide_timeout = 0;
 
3246
                return FALSE;
 
3247
        }
 
3248
 
 
3249
        /* keep coming back until the animation has finished.
 
3250
         * FIXME: we should really remove the timeout/idle
 
3251
         *        completely and re-instate it when the
 
3252
         *        animation has finished.
 
3253
         */
 
3254
        if (toplevel->priv->animating)
 
3255
                return TRUE;
 
3256
 
 
3257
        panel_toplevel_hide (toplevel, TRUE, -1);
 
3258
 
 
3259
        toplevel->priv->hide_timeout = 0;
 
3260
 
 
3261
        return FALSE;
 
3262
}
 
3263
 
 
3264
void
 
3265
panel_toplevel_unhide (PanelToplevel *toplevel)
 
3266
{
 
3267
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
3268
 
 
3269
        if (toplevel->priv->state == PANEL_STATE_NORMAL)
 
3270
                return;
 
3271
 
 
3272
        toplevel->priv->state = PANEL_STATE_NORMAL;
 
3273
 
 
3274
        panel_toplevel_update_hide_buttons (toplevel);
 
3275
 
 
3276
        if (toplevel->priv->animate && gtk_widget_get_realized (GTK_WIDGET (toplevel)))
 
3277
                panel_toplevel_start_animation (toplevel);
 
3278
 
 
3279
        gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
3280
 
 
3281
        if (!toplevel->priv->animate)
 
3282
                g_signal_emit (toplevel, toplevel_signals [UNHIDE_SIGNAL], 0);
 
3283
}
 
3284
 
 
3285
static gboolean
 
3286
panel_toplevel_auto_unhide_timeout_handler (PanelToplevel *toplevel)
 
3287
{
 
3288
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
3289
 
 
3290
        /* keep coming back until the animation has finished.
 
3291
         * FIXME: we should really remove the timeout/idle
 
3292
         *        completely and re-instate it when the
 
3293
         *        animation has finished.
 
3294
         */
 
3295
        if (toplevel->priv->animating)
 
3296
                return TRUE;
 
3297
 
 
3298
        if (!toplevel->priv->animate)
 
3299
                toplevel->priv->initial_animation_done = TRUE;
 
3300
 
 
3301
        /* initial animation for auto-hidden panels: we need to unhide and hide
 
3302
         * again to get at the right size */
 
3303
        if (!toplevel->priv->initial_animation_done &&
 
3304
            toplevel->priv->auto_hide) {
 
3305
                toplevel->priv->unhide_timeout = 0;
 
3306
                panel_toplevel_unhide (toplevel);
 
3307
                panel_toplevel_hide (toplevel, TRUE, -1);
 
3308
                return FALSE;
 
3309
        }
 
3310
 
 
3311
        if (!panel_toplevel_contains_pointer (toplevel) &&
 
3312
            toplevel->priv->auto_hide) {
 
3313
                toplevel->priv->unhide_timeout = 0;
 
3314
                return FALSE;
 
3315
        }
 
3316
 
 
3317
        panel_toplevel_unhide (toplevel);
 
3318
 
 
3319
        toplevel->priv->unhide_timeout = 0;
 
3320
 
 
3321
        return FALSE;
 
3322
}
 
3323
 
 
3324
void
 
3325
panel_toplevel_queue_auto_hide (PanelToplevel *toplevel)
 
3326
{
 
3327
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
3328
 
 
3329
        if (!toplevel->priv->auto_hide ||
 
3330
            panel_toplevel_contains_pointer (toplevel) ||
 
3331
            panel_toplevel_get_autohide_disabled (toplevel))
 
3332
          return;
 
3333
 
 
3334
        if (toplevel->priv->unhide_timeout)
 
3335
                g_source_remove (toplevel->priv->unhide_timeout);
 
3336
        toplevel->priv->unhide_timeout = 0;
 
3337
 
 
3338
        if (toplevel->priv->hide_timeout ||
 
3339
            toplevel->priv->state != PANEL_STATE_NORMAL)
 
3340
                return;
 
3341
 
 
3342
        if (toplevel->priv->hide_delay > 0)
 
3343
                toplevel->priv->hide_timeout = 
 
3344
                        g_timeout_add (toplevel->priv->hide_delay,
 
3345
                                       (GSourceFunc) panel_toplevel_auto_hide_timeout_handler,
 
3346
                                       toplevel);
 
3347
        else
 
3348
                toplevel->priv->hide_timeout = 
 
3349
                        g_idle_add ((GSourceFunc) panel_toplevel_auto_hide_timeout_handler,
 
3350
                                    toplevel);
 
3351
}
 
3352
 
 
3353
void
 
3354
panel_toplevel_queue_auto_unhide (PanelToplevel *toplevel)
 
3355
{
 
3356
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
3357
 
 
3358
        if (toplevel->priv->unhide_timeout)
 
3359
                return;
 
3360
 
 
3361
        if (toplevel->priv->hide_timeout)
 
3362
                g_source_remove (toplevel->priv->hide_timeout);
 
3363
        toplevel->priv->hide_timeout = 0;
 
3364
 
 
3365
        if (toplevel->priv->state != PANEL_STATE_AUTO_HIDDEN)
 
3366
                return;
 
3367
 
 
3368
        if (toplevel->priv->unhide_delay > 0)
 
3369
                toplevel->priv->unhide_timeout = 
 
3370
                        g_timeout_add (toplevel->priv->unhide_delay,
 
3371
                                       (GSourceFunc) panel_toplevel_auto_unhide_timeout_handler,
 
3372
                                       toplevel);
 
3373
        else
 
3374
                toplevel->priv->unhide_timeout = 
 
3375
                        g_idle_add ((GSourceFunc) panel_toplevel_auto_unhide_timeout_handler,
 
3376
                                    toplevel);
 
3377
}
 
3378
 
 
3379
void
 
3380
panel_toplevel_queue_initial_unhide (PanelToplevel *toplevel)
 
3381
{
 
3382
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
3383
 
 
3384
        if (toplevel->priv->initial_animation_done)
 
3385
                return;
 
3386
 
 
3387
        if (toplevel->priv->unhide_timeout)
 
3388
                return;
 
3389
 
 
3390
        toplevel->priv->unhide_timeout =
 
3391
                g_idle_add ((GSourceFunc) panel_toplevel_auto_unhide_timeout_handler,
 
3392
                            toplevel);
 
3393
}
 
3394
 
 
3395
static gboolean
 
3396
panel_toplevel_enter_notify_event (GtkWidget        *widget,
 
3397
                                   GdkEventCrossing *event)
 
3398
{
 
3399
        PanelToplevel *toplevel;
 
3400
 
 
3401
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE);
 
3402
 
 
3403
        toplevel = PANEL_TOPLEVEL (widget);
 
3404
 
 
3405
        if (toplevel->priv->auto_hide && event->detail != GDK_NOTIFY_INFERIOR)
 
3406
                panel_toplevel_queue_auto_unhide (toplevel);
 
3407
 
 
3408
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->enter_notify_event)
 
3409
                return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->enter_notify_event (widget, event);
 
3410
 
 
3411
        return FALSE;
 
3412
}
 
3413
 
 
3414
static gboolean
 
3415
panel_toplevel_leave_notify_event (GtkWidget        *widget,
 
3416
                                   GdkEventCrossing *event)
 
3417
{
 
3418
        PanelToplevel *toplevel;
 
3419
 
 
3420
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (widget), FALSE);
 
3421
 
 
3422
        toplevel = PANEL_TOPLEVEL (widget);
 
3423
 
 
3424
        if (toplevel->priv->auto_hide && event->detail != GDK_NOTIFY_INFERIOR)
 
3425
                panel_toplevel_queue_auto_hide (toplevel);
 
3426
 
 
3427
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->leave_notify_event)
 
3428
                return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->leave_notify_event (widget, event);
 
3429
 
 
3430
        return FALSE;
 
3431
}
 
3432
 
 
3433
static gboolean
 
3434
panel_toplevel_focus_in_event (GtkWidget     *widget,
 
3435
                               GdkEventFocus *event)
 
3436
{
 
3437
        PanelToplevel *toplevel = PANEL_TOPLEVEL (widget);
 
3438
        
 
3439
        if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN)
 
3440
                panel_toplevel_unhide (toplevel);
 
3441
 
 
3442
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_in_event)
 
3443
                return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_in_event (widget, event);
 
3444
 
 
3445
        return FALSE;
 
3446
}
 
3447
 
 
3448
static gboolean
 
3449
panel_toplevel_focus_out_event (GtkWidget     *widget,
 
3450
                                GdkEventFocus *event)
 
3451
{
 
3452
        PanelToplevel *toplevel = PANEL_TOPLEVEL (widget);
 
3453
 
 
3454
        /* It appears that sometimes we don't get a leave notify event,
 
3455
           but just a focus in/out, so queue the autohide in that case.
 
3456
           If the pointer is inside the panel then obviously we won't hide */
 
3457
        if (toplevel->priv->auto_hide)
 
3458
                panel_toplevel_queue_auto_hide (toplevel);
 
3459
 
 
3460
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_out_event)
 
3461
                return GTK_WIDGET_CLASS (panel_toplevel_parent_class)->focus_out_event (widget, event);
 
3462
 
 
3463
        return FALSE;
 
3464
}
 
3465
 
 
3466
static void
 
3467
panel_toplevel_style_updated (GtkWidget *widget)
 
3468
{
 
3469
        panel_toplevel_update_hide_buttons (PANEL_TOPLEVEL (widget));
 
3470
 
 
3471
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->style_updated)
 
3472
                GTK_WIDGET_CLASS (panel_toplevel_parent_class)->style_updated (widget);
 
3473
}
 
3474
 
 
3475
static void
 
3476
panel_toplevel_drag_threshold_changed (PanelToplevel *toplevel)
 
3477
{
 
3478
        int threshold;
 
3479
 
 
3480
        threshold = 0;
 
3481
        g_object_get (G_OBJECT (toplevel->priv->gtk_settings),
 
3482
                      "gtk-dnd-drag-threshold", &threshold,
 
3483
                      NULL);
 
3484
 
 
3485
        if (threshold)
 
3486
                toplevel->priv->snap_tolerance = threshold * SNAP_TOLERANCE_FACTOR;
 
3487
}
 
3488
 
 
3489
static void
 
3490
panel_toplevel_enable_animations_changed (PanelToplevel *toplevel)
 
3491
{
 
3492
        gboolean enable_animations;
 
3493
 
 
3494
        enable_animations = TRUE;
 
3495
        g_object_get (G_OBJECT (toplevel->priv->gtk_settings),
 
3496
                      "gtk-enable-animations", &enable_animations,
 
3497
                      NULL);
 
3498
 
 
3499
        panel_toplevel_set_animate (toplevel, enable_animations);
 
3500
}
 
3501
 
 
3502
static void
 
3503
panel_toplevel_disconnect_gtk_settings (PanelToplevel *toplevel)
 
3504
{
 
3505
        if (!toplevel->priv->gtk_settings)
 
3506
                return;
 
3507
 
 
3508
        g_signal_handlers_disconnect_by_func (toplevel->priv->gtk_settings,
 
3509
                                              G_CALLBACK (panel_toplevel_drag_threshold_changed),
 
3510
                                              toplevel);
 
3511
        g_signal_handlers_disconnect_by_func (toplevel->priv->gtk_settings,
 
3512
                                              G_CALLBACK (panel_toplevel_enable_animations_changed),
 
3513
                                              toplevel);
 
3514
}
 
3515
 
 
3516
static void
 
3517
panel_toplevel_update_gtk_settings (PanelToplevel *toplevel)
 
3518
{
 
3519
        panel_toplevel_disconnect_gtk_settings (toplevel);
 
3520
 
 
3521
        toplevel->priv->gtk_settings = gtk_widget_get_settings (GTK_WIDGET (toplevel->priv->panel_widget));
 
3522
 
 
3523
        g_signal_connect_swapped (G_OBJECT (toplevel->priv->gtk_settings),
 
3524
                                  "notify::gtk-dnd-drag-threshold",
 
3525
                                  G_CALLBACK (panel_toplevel_drag_threshold_changed),
 
3526
                                  toplevel);
 
3527
 
 
3528
        panel_toplevel_drag_threshold_changed (toplevel);
 
3529
 
 
3530
        g_signal_connect_swapped (G_OBJECT (toplevel->priv->gtk_settings),
 
3531
                                  "notify::gtk-enable-animations",
 
3532
                                  G_CALLBACK (panel_toplevel_enable_animations_changed),
 
3533
                                  toplevel);
 
3534
 
 
3535
        panel_toplevel_enable_animations_changed (toplevel);
 
3536
}
 
3537
 
 
3538
static void
 
3539
panel_toplevel_screen_changed (GtkWidget *widget,
 
3540
                               GdkScreen *previous_screen)
 
3541
{
 
3542
        panel_toplevel_update_gtk_settings (PANEL_TOPLEVEL (widget));
 
3543
 
 
3544
        if (GTK_WIDGET_CLASS (panel_toplevel_parent_class)->screen_changed)
 
3545
                GTK_WIDGET_CLASS (panel_toplevel_parent_class)->screen_changed (widget, previous_screen);
 
3546
 
 
3547
        gtk_widget_queue_resize (widget);
 
3548
}
 
3549
 
 
3550
static GObject *
 
3551
panel_toplevel_constructor (GType                  type,
 
3552
                            guint                  n_construct_properties,
 
3553
                            GObjectConstructParam *construct_properties)
 
3554
{
 
3555
        GObject       *obj;
 
3556
        PanelToplevel *toplevel;
 
3557
 
 
3558
        obj = G_OBJECT_CLASS (panel_toplevel_parent_class)->constructor (type,
 
3559
                                                                         n_construct_properties,
 
3560
                                                                         construct_properties);
 
3561
 
 
3562
        toplevel = PANEL_TOPLEVEL (obj);
 
3563
 
 
3564
        /* We can't do that in init() as init() will set the properties to
 
3565
         * their default, and this would write to gsettings */
 
3566
        panel_toplevel_bind_gsettings (toplevel);
 
3567
 
 
3568
        return obj;
 
3569
}
 
3570
 
 
3571
static void
 
3572
panel_toplevel_set_property (GObject      *object,
 
3573
                             guint         prop_id,
 
3574
                             const GValue *value,
 
3575
                             GParamSpec   *pspec)
 
3576
{
 
3577
        PanelToplevel *toplevel;
 
3578
 
 
3579
        g_return_if_fail (PANEL_IS_TOPLEVEL (object));
 
3580
 
 
3581
        toplevel = PANEL_TOPLEVEL (object);
 
3582
 
 
3583
        switch (prop_id) {
 
3584
        case PROP_TOPLEVEL_ID:
 
3585
                panel_toplevel_set_toplevel_id (toplevel, g_value_get_string (value));
 
3586
                break;
 
3587
        case PROP_SETTINGS_PATH:
 
3588
                panel_toplevel_set_settings_path (toplevel, g_value_get_string (value));
 
3589
                break;
 
3590
        case PROP_NAME:
 
3591
                panel_toplevel_set_name (toplevel, g_value_get_string (value));
 
3592
                break;
 
3593
        case PROP_EXPAND:
 
3594
                panel_toplevel_set_expand (toplevel, g_value_get_boolean (value));
 
3595
                break;
 
3596
        case PROP_ORIENTATION:
 
3597
                panel_toplevel_set_orientation (toplevel, g_value_get_enum (value));
 
3598
                break;
 
3599
        case PROP_SIZE:
 
3600
                panel_toplevel_set_size (toplevel, g_value_get_int (value));
 
3601
                break;
 
3602
        case PROP_X:
 
3603
                panel_toplevel_set_x (toplevel,
 
3604
                                      g_value_get_int (value),
 
3605
                                      toplevel->priv->x_right,
 
3606
                                      toplevel->priv->x_centered);
 
3607
                break;
 
3608
        case PROP_X_RIGHT:
 
3609
                panel_toplevel_set_x (toplevel,
 
3610
                                      toplevel->priv->x,
 
3611
                                      g_value_get_int (value),
 
3612
                                      toplevel->priv->x_centered);
 
3613
                break;
 
3614
        case PROP_X_CENTERED:
 
3615
                panel_toplevel_set_x (toplevel,
 
3616
                                      toplevel->priv->x,
 
3617
                                      toplevel->priv->x_right,
 
3618
                                      g_value_get_boolean (value));
 
3619
                break;
 
3620
        case PROP_Y:
 
3621
                panel_toplevel_set_y (toplevel,
 
3622
                                      g_value_get_int (value),
 
3623
                                      toplevel->priv->y_bottom,
 
3624
                                      toplevel->priv->y_centered);
 
3625
                break;
 
3626
        case PROP_Y_BOTTOM:
 
3627
                panel_toplevel_set_y (toplevel,
 
3628
                                      toplevel->priv->y,
 
3629
                                      g_value_get_int (value),
 
3630
                                      toplevel->priv->y_centered);
 
3631
                break;
 
3632
        case PROP_Y_CENTERED:
 
3633
                panel_toplevel_set_y (toplevel,
 
3634
                                      toplevel->priv->y,
 
3635
                                      toplevel->priv->y_bottom,
 
3636
                                      g_value_get_boolean (value));
 
3637
                break;
 
3638
        case PROP_MONITOR:
 
3639
                panel_toplevel_set_monitor (toplevel, g_value_get_int (value));
 
3640
                break;
 
3641
        case PROP_AUTOHIDE:
 
3642
                panel_toplevel_set_auto_hide (toplevel, g_value_get_boolean (value));
 
3643
                break;
 
3644
        case PROP_HIDE_DELAY:
 
3645
                panel_toplevel_set_hide_delay (toplevel, g_value_get_int (value));
 
3646
                break;
 
3647
        case PROP_UNHIDE_DELAY:
 
3648
                panel_toplevel_set_unhide_delay (toplevel, g_value_get_int (value));
 
3649
                break;
 
3650
        case PROP_AUTOHIDE_SIZE:
 
3651
                panel_toplevel_set_auto_hide_size (toplevel, g_value_get_int (value));
 
3652
                break;
 
3653
        case PROP_ANIMATE:
 
3654
                panel_toplevel_set_animate (toplevel, g_value_get_boolean (value));
 
3655
                break;
 
3656
        case PROP_ANIMATION_SPEED:
 
3657
                panel_toplevel_set_animation_speed (toplevel, g_value_get_enum (value));
 
3658
                break;
 
3659
        case PROP_BUTTONS_ENABLED:
 
3660
                panel_toplevel_set_enable_buttons (toplevel, g_value_get_boolean (value));
 
3661
                break;
 
3662
        case PROP_ARROWS_ENABLED:
 
3663
                panel_toplevel_set_enable_arrows (toplevel, g_value_get_boolean (value));
 
3664
                break;
 
3665
        default:
 
3666
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
3667
                break;
 
3668
        }
 
3669
}
 
3670
 
 
3671
static void
 
3672
panel_toplevel_get_property (GObject    *object,
 
3673
                             guint       prop_id,
 
3674
                             GValue     *value,
 
3675
                             GParamSpec *pspec)
 
3676
{
 
3677
        PanelToplevel *toplevel;
 
3678
 
 
3679
        g_return_if_fail (PANEL_IS_TOPLEVEL (object));
 
3680
 
 
3681
        toplevel = PANEL_TOPLEVEL (object);
 
3682
 
 
3683
        switch (prop_id) {
 
3684
        case PROP_TOPLEVEL_ID:
 
3685
                g_value_set_string (value, toplevel->priv->toplevel_id);
 
3686
                break;
 
3687
        case PROP_SETTINGS_PATH:
 
3688
                g_value_set_string (value, toplevel->priv->settings_path);
 
3689
                break;
 
3690
        case PROP_NAME:
 
3691
                g_value_set_string (value, panel_toplevel_get_name (toplevel));
 
3692
                break;
 
3693
        case PROP_EXPAND:
 
3694
                g_value_set_boolean (value, toplevel->priv->expand);
 
3695
                break;
 
3696
        case PROP_ORIENTATION:
 
3697
                g_value_set_enum (value, toplevel->priv->orientation);
 
3698
                break;
 
3699
        case PROP_SIZE:
 
3700
                g_value_set_int (value, toplevel->priv->size);
 
3701
                break;
 
3702
        case PROP_X:
 
3703
                g_value_set_int (value, toplevel->priv->x);
 
3704
                break;
 
3705
        case PROP_X_RIGHT:
 
3706
                g_value_set_int (value, toplevel->priv->x_right);
 
3707
                break;
 
3708
        case PROP_X_CENTERED:
 
3709
                g_value_set_boolean (value, toplevel->priv->x_centered);
 
3710
                break;
 
3711
        case PROP_Y:
 
3712
                g_value_set_int (value, toplevel->priv->y);
 
3713
                break;
 
3714
        case PROP_Y_BOTTOM:
 
3715
                g_value_set_int (value, toplevel->priv->y_bottom);
 
3716
                break;
 
3717
        case PROP_Y_CENTERED:
 
3718
                g_value_set_boolean (value, toplevel->priv->y_centered);
 
3719
                break;
 
3720
        case PROP_MONITOR:
 
3721
                g_value_set_int (value, toplevel->priv->monitor);
 
3722
                break;
 
3723
        case PROP_AUTOHIDE:
 
3724
                g_value_set_boolean (value, toplevel->priv->auto_hide);
 
3725
                break;
 
3726
        case PROP_HIDE_DELAY:
 
3727
                g_value_set_int (value, toplevel->priv->hide_delay);
 
3728
                break;
 
3729
        case PROP_UNHIDE_DELAY:
 
3730
                g_value_set_int (value, toplevel->priv->unhide_delay);
 
3731
                break;
 
3732
        case PROP_AUTOHIDE_SIZE:
 
3733
                g_value_set_int (value, toplevel->priv->auto_hide_size);
 
3734
                break;
 
3735
        case PROP_ANIMATE:
 
3736
                g_value_set_boolean (value, toplevel->priv->animate);
 
3737
                break;
 
3738
        case PROP_ANIMATION_SPEED:
 
3739
                g_value_set_enum (value, toplevel->priv->animation_speed);
 
3740
                break;
 
3741
        case PROP_BUTTONS_ENABLED:
 
3742
                g_value_set_boolean (value, toplevel->priv->buttons_enabled);
 
3743
                break;
 
3744
        case PROP_ARROWS_ENABLED:
 
3745
                g_value_set_boolean (value, toplevel->priv->arrows_enabled);
 
3746
                break;
 
3747
        default:
 
3748
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
3749
                break;
 
3750
        }
 
3751
}
 
3752
 
 
3753
static void
 
3754
panel_toplevel_finalize (GObject *object)
 
3755
{
 
3756
        PanelToplevel *toplevel = (PanelToplevel *) object;
 
3757
 
 
3758
        panel_struts_unregister_strut (toplevel);
 
3759
 
 
3760
        toplevel_list = g_slist_remove (toplevel_list, toplevel);
 
3761
 
 
3762
        panel_toplevel_disconnect_gtk_settings (toplevel);
 
3763
        toplevel->priv->gtk_settings = NULL;
 
3764
 
 
3765
        if (toplevel->priv->description)
 
3766
                g_free (toplevel->priv->description);
 
3767
        toplevel->priv->description = NULL;
 
3768
 
 
3769
        if (toplevel->priv->name)
 
3770
                g_free (toplevel->priv->name);
 
3771
        toplevel->priv->name = NULL;
 
3772
 
 
3773
        if (toplevel->priv->apply_delayed_id)
 
3774
                g_source_remove (toplevel->priv->apply_delayed_id);
 
3775
        toplevel->priv->apply_delayed_id = 0;
 
3776
 
 
3777
        if (toplevel->priv->delayed_settings) {
 
3778
                g_settings_apply (toplevel->priv->delayed_settings);
 
3779
                g_object_unref (toplevel->priv->delayed_settings);
 
3780
        }
 
3781
        toplevel->priv->delayed_settings= NULL;
 
3782
 
 
3783
        if (toplevel->priv->settings)
 
3784
                g_object_unref (toplevel->priv->settings);
 
3785
        toplevel->priv->settings= NULL;
 
3786
 
 
3787
        if (toplevel->priv->settings_path)
 
3788
                g_free (toplevel->priv->settings_path);
 
3789
        toplevel->priv->settings_path = NULL;
 
3790
 
 
3791
        if (toplevel->priv->toplevel_id)
 
3792
                g_free (toplevel->priv->toplevel_id);
 
3793
        toplevel->priv->toplevel_id = NULL;
 
3794
 
 
3795
        G_OBJECT_CLASS (panel_toplevel_parent_class)->finalize (object);
 
3796
}
 
3797
 
 
3798
static void
 
3799
panel_toplevel_class_init (PanelToplevelClass *klass)
 
3800
{
 
3801
        GObjectClass      *gobject_class   = (GObjectClass      *) klass;
 
3802
        GtkWidgetClass    *widget_class    = (GtkWidgetClass    *) klass;
 
3803
        GtkContainerClass *container_class = (GtkContainerClass *) klass;
 
3804
        GtkBindingSet     *binding_set;
 
3805
 
 
3806
        binding_set = gtk_binding_set_by_class (klass);
 
3807
 
 
3808
        gobject_class->constructor  = panel_toplevel_constructor;
 
3809
        gobject_class->set_property = panel_toplevel_set_property;
 
3810
        gobject_class->get_property = panel_toplevel_get_property;
 
3811
        gobject_class->dispose      = panel_toplevel_dispose;
 
3812
        gobject_class->finalize     = panel_toplevel_finalize;
 
3813
 
 
3814
        widget_class->realize              = panel_toplevel_realize;
 
3815
        widget_class->unrealize            = panel_toplevel_unrealize;
 
3816
        widget_class->get_preferred_width  = panel_toplevel_get_preferred_width;
 
3817
        widget_class->get_preferred_height = panel_toplevel_get_preferred_height;
 
3818
        widget_class->size_allocate        = panel_toplevel_size_allocate;
 
3819
        widget_class->draw                 = panel_toplevel_draw;
 
3820
        widget_class->button_press_event   = panel_toplevel_button_press_event;
 
3821
        widget_class->button_release_event = panel_toplevel_button_release_event;
 
3822
        widget_class->key_press_event      = panel_toplevel_key_press_event;
 
3823
        widget_class->motion_notify_event  = panel_toplevel_motion_notify_event;
 
3824
        widget_class->enter_notify_event   = panel_toplevel_enter_notify_event;
 
3825
        widget_class->leave_notify_event   = panel_toplevel_leave_notify_event;
 
3826
        widget_class->screen_changed       = panel_toplevel_screen_changed;
 
3827
        widget_class->focus_in_event       = panel_toplevel_focus_in_event;
 
3828
        widget_class->focus_out_event      = panel_toplevel_focus_out_event;
 
3829
        widget_class->style_updated        = panel_toplevel_style_updated;
 
3830
 
 
3831
        container_class->check_resize = panel_toplevel_check_resize;
 
3832
 
 
3833
        klass->hiding           = NULL;
 
3834
        klass->unhiding         = NULL;
 
3835
        klass->popup_panel_menu = panel_toplevel_popup_panel_menu;
 
3836
        klass->toggle_expand    = panel_toplevel_toggle_expand;
 
3837
        klass->expand           = panel_toplevel_expand;
 
3838
        klass->unexpand         = panel_toplevel_unexpand;
 
3839
        klass->toggle_hidden    = panel_toplevel_toggle_hidden;
 
3840
        klass->begin_move       = panel_toplevel_begin_move;
 
3841
        klass->begin_resize     = panel_toplevel_begin_resize;
 
3842
 
 
3843
        g_type_class_add_private (klass, sizeof (PanelToplevelPrivate));
 
3844
 
 
3845
        g_object_class_install_property (
 
3846
                gobject_class,
 
3847
                PROP_TOPLEVEL_ID,
 
3848
                g_param_spec_string (
 
3849
                        "toplevel-id",
 
3850
                        "Panel identifier",
 
3851
                        "Unique identifier of this panel",
 
3852
                        NULL,
 
3853
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
3854
 
 
3855
        g_object_class_install_property (
 
3856
                gobject_class,
 
3857
                PROP_SETTINGS_PATH,
 
3858
                g_param_spec_string (
 
3859
                        "settings-path",
 
3860
                        "GSettings path",
 
3861
                        "The GSettings path used for this panel",
 
3862
                        NULL,
 
3863
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
3864
 
 
3865
        g_object_class_install_property (
 
3866
                gobject_class,
 
3867
                PROP_NAME,
 
3868
                g_param_spec_string (
 
3869
                        "name",
 
3870
                        "Name",
 
3871
                        "The name of this panel",
 
3872
                        NULL,
 
3873
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3874
 
 
3875
        g_object_class_install_property (
 
3876
                gobject_class,
 
3877
                PROP_EXPAND,
 
3878
                g_param_spec_boolean (
 
3879
                        "expand",
 
3880
                        "Expand",
 
3881
                        "Expand to take up the full monitor width/height",
 
3882
                        TRUE,
 
3883
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3884
 
 
3885
        g_object_class_install_property (
 
3886
                gobject_class,
 
3887
                PROP_ORIENTATION,
 
3888
                g_param_spec_enum (
 
3889
                        "orientation",
 
3890
                        "Orientation",
 
3891
                        "The orientation of the panel",
 
3892
                        PANEL_TYPE_ORIENTATION,
 
3893
                        PANEL_ORIENTATION_TOP,
 
3894
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3895
 
 
3896
        g_object_class_install_property (
 
3897
                gobject_class,
 
3898
                PROP_SIZE,
 
3899
                g_param_spec_int (
 
3900
                        "size",
 
3901
                        "Size",
 
3902
                        "The height (or width when vertical) of the panel",
 
3903
                        0,
 
3904
                        G_MAXINT,
 
3905
                        DEFAULT_SIZE,
 
3906
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3907
 
 
3908
 
 
3909
        g_object_class_install_property (
 
3910
                gobject_class,
 
3911
                PROP_X,
 
3912
                g_param_spec_int (
 
3913
                        "x",
 
3914
                        "X position",
 
3915
                        "The X position of the panel",
 
3916
                        0,
 
3917
                        G_MAXINT,
 
3918
                        0,
 
3919
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3920
 
 
3921
        g_object_class_install_property (
 
3922
                gobject_class,
 
3923
                PROP_X_RIGHT,
 
3924
                g_param_spec_int (
 
3925
                        "x-right",
 
3926
                        "X position, from the right",
 
3927
                        "The X position of the panel, starting from the right of the screen",
 
3928
                        -1,
 
3929
                        G_MAXINT,
 
3930
                        -1,
 
3931
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3932
 
 
3933
        g_object_class_install_property (
 
3934
                gobject_class,
 
3935
                PROP_X_CENTERED,
 
3936
                g_param_spec_boolean (
 
3937
                        "x-centered",
 
3938
                        "X centered",
 
3939
                        "The x co-ordinate is relative to center screen",
 
3940
                        FALSE,
 
3941
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3942
 
 
3943
        g_object_class_install_property (
 
3944
                gobject_class,
 
3945
                PROP_Y,
 
3946
                g_param_spec_int (
 
3947
                        "y",
 
3948
                        "Y position",
 
3949
                        "The Y position of the panel",
 
3950
                        0,
 
3951
                        G_MAXINT,
 
3952
                        0,
 
3953
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3954
 
 
3955
        g_object_class_install_property (
 
3956
                gobject_class,
 
3957
                PROP_Y_BOTTOM,
 
3958
                g_param_spec_int (
 
3959
                        "y-bottom",
 
3960
                        "Y position, from the bottom",
 
3961
                        "The Y position of the panel, starting from the bottom of the screen",
 
3962
                        -1,
 
3963
                        G_MAXINT,
 
3964
                        -1,
 
3965
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3966
 
 
3967
        g_object_class_install_property (
 
3968
                gobject_class,
 
3969
                PROP_Y_CENTERED,
 
3970
                g_param_spec_boolean (
 
3971
                        "y-centered",
 
3972
                        "Y centered",
 
3973
                        "The y co-ordinate is relative to center screen",
 
3974
                        FALSE,
 
3975
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3976
 
 
3977
        g_object_class_install_property (
 
3978
                gobject_class,
 
3979
                PROP_MONITOR,
 
3980
                g_param_spec_int (
 
3981
                        "monitor",
 
3982
                        "Xinerama monitor",
 
3983
                        "The monitor (in terms of Xinerama) which the panel is on",
 
3984
                        0,
 
3985
                        G_MAXINT,
 
3986
                        0,
 
3987
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3988
 
 
3989
        g_object_class_install_property (
 
3990
                gobject_class,
 
3991
                PROP_AUTOHIDE,
 
3992
                g_param_spec_boolean (
 
3993
                        "auto-hide",
 
3994
                        "Auto hide",
 
3995
                        "Automatically hide the panel when the mouse leaves the panel",
 
3996
                        FALSE,
 
3997
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
3998
 
 
3999
        g_object_class_install_property (
 
4000
                gobject_class,
 
4001
                PROP_HIDE_DELAY,
 
4002
                g_param_spec_int (
 
4003
                        "hide-delay",
 
4004
                        "Hide delay",
 
4005
                        "The number of milliseconds to delay before automatically hiding",
 
4006
                        0,
 
4007
                        G_MAXINT,
 
4008
                        DEFAULT_HIDE_DELAY,
 
4009
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
4010
 
 
4011
        g_object_class_install_property (
 
4012
                gobject_class,
 
4013
                PROP_UNHIDE_DELAY,
 
4014
                g_param_spec_int (
 
4015
                        "unhide-delay",
 
4016
                        "Un-hide delay",
 
4017
                        "The number of milliseconds to delay before automatically un-hiding",
 
4018
                        0,
 
4019
                        G_MAXINT,
 
4020
                        DEFAULT_UNHIDE_DELAY,
 
4021
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
4022
 
 
4023
        g_object_class_install_property (
 
4024
                gobject_class,
 
4025
                PROP_AUTOHIDE_SIZE,
 
4026
                g_param_spec_int (
 
4027
                        "auto-hide-size",
 
4028
                        "Auto-hide size",
 
4029
                        "The number of pixels visible when the panel has been automatically hidden",
 
4030
                        1,
 
4031
                        G_MAXINT,
 
4032
                        DEFAULT_AUTO_HIDE_SIZE,
 
4033
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
4034
 
 
4035
        g_object_class_install_property (
 
4036
                gobject_class,
 
4037
                PROP_ANIMATE,
 
4038
                g_param_spec_boolean (
 
4039
                        "animate",
 
4040
                        "Animate",
 
4041
                        "Enable hiding/showing animations",
 
4042
                        TRUE,
 
4043
                        G_PARAM_READABLE));
 
4044
 
 
4045
        g_object_class_install_property (
 
4046
                gobject_class,
 
4047
                PROP_ANIMATION_SPEED,
 
4048
                g_param_spec_enum (
 
4049
                        "animation-speed",
 
4050
                        "Animation Speed",
 
4051
                        "The speed at which to animate panel hiding/showing",
 
4052
                        PANEL_TYPE_ANIMATION_SPEED,
 
4053
                        PANEL_ANIMATION_MEDIUM,
 
4054
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
4055
 
 
4056
        g_object_class_install_property (
 
4057
                gobject_class,
 
4058
                PROP_BUTTONS_ENABLED,
 
4059
                g_param_spec_boolean (
 
4060
                        "buttons-enabled",
 
4061
                        "Buttons Enabled",
 
4062
                        "Enable hide/show buttons",
 
4063
                        TRUE,
 
4064
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
4065
 
 
4066
        g_object_class_install_property (
 
4067
                gobject_class,
 
4068
                PROP_ARROWS_ENABLED,
 
4069
                g_param_spec_boolean (
 
4070
                        "arrows-enabled",
 
4071
                        "Arrows Enabled",
 
4072
                        "Enable arrows on hide/show buttons",
 
4073
                        TRUE,
 
4074
                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 
4075
 
 
4076
        gtk_widget_class_install_style_property (
 
4077
                widget_class,
 
4078
                g_param_spec_int (
 
4079
                        "arrow-size",
 
4080
                        "Arrow Size",
 
4081
                        "The size of the arrows on the hide/show buttons",
 
4082
                        0,
 
4083
                        G_MAXINT,
 
4084
                        DEFAULT_ARROW_SIZE,
 
4085
                        G_PARAM_READABLE));
 
4086
 
 
4087
        toplevel_signals [HIDE_SIGNAL] =
 
4088
                g_signal_new ("hiding",
 
4089
                              G_TYPE_FROM_CLASS (gobject_class),
 
4090
                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 
4091
                              G_STRUCT_OFFSET (PanelToplevelClass, hiding),
 
4092
                              NULL,
 
4093
                              NULL,
 
4094
                              g_cclosure_marshal_VOID__VOID,
 
4095
                              G_TYPE_NONE,
 
4096
                              0);
 
4097
 
 
4098
        toplevel_signals [UNHIDE_SIGNAL] =
 
4099
                g_signal_new ("unhiding",
 
4100
                              G_TYPE_FROM_CLASS (gobject_class),
 
4101
                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 
4102
                              G_STRUCT_OFFSET (PanelToplevelClass, unhiding),
 
4103
                              NULL,
 
4104
                              NULL,
 
4105
                              g_cclosure_marshal_VOID__VOID,
 
4106
                              G_TYPE_NONE,
 
4107
                              0);
 
4108
 
 
4109
        toplevel_signals [POPUP_PANEL_MENU_SIGNAL] =
 
4110
                g_signal_new ("popup-panel-menu",
 
4111
                              G_TYPE_FROM_CLASS (gobject_class),
 
4112
                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
4113
                              G_STRUCT_OFFSET (PanelToplevelClass, popup_panel_menu),
 
4114
                              NULL,
 
4115
                              NULL,
 
4116
                              panel_marshal_BOOLEAN__VOID,
 
4117
                              G_TYPE_BOOLEAN,
 
4118
                              0);
 
4119
 
 
4120
        toplevel_signals [TOGGLE_EXPAND_SIGNAL] =
 
4121
                g_signal_new ("toggle-expand",
 
4122
                              G_TYPE_FROM_CLASS (gobject_class),
 
4123
                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
4124
                              G_STRUCT_OFFSET (PanelToplevelClass, toggle_expand),
 
4125
                              NULL,
 
4126
                              NULL,
 
4127
                              panel_marshal_BOOLEAN__VOID,
 
4128
                              G_TYPE_BOOLEAN,
 
4129
                              0);
 
4130
 
 
4131
        toplevel_signals [EXPAND_SIGNAL] =
 
4132
                g_signal_new ("expand",
 
4133
                              G_TYPE_FROM_CLASS (gobject_class),
 
4134
                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
4135
                              G_STRUCT_OFFSET (PanelToplevelClass, expand),
 
4136
                              NULL,
 
4137
                              NULL,
 
4138
                              panel_marshal_BOOLEAN__VOID,
 
4139
                              G_TYPE_BOOLEAN,
 
4140
                              0);
 
4141
 
 
4142
        toplevel_signals [UNEXPAND_SIGNAL] =
 
4143
                g_signal_new ("unexpand",
 
4144
                              G_TYPE_FROM_CLASS (gobject_class),
 
4145
                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
4146
                              G_STRUCT_OFFSET (PanelToplevelClass, unexpand),
 
4147
                              NULL,
 
4148
                              NULL,
 
4149
                              panel_marshal_BOOLEAN__VOID,
 
4150
                              G_TYPE_BOOLEAN,
 
4151
                              0);
 
4152
 
 
4153
        toplevel_signals [TOGGLE_HIDDEN_SIGNAL] =
 
4154
                g_signal_new ("toggle-hidden",
 
4155
                              G_TYPE_FROM_CLASS (gobject_class),
 
4156
                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
4157
                              G_STRUCT_OFFSET (PanelToplevelClass, toggle_hidden),
 
4158
                              NULL,
 
4159
                              NULL,
 
4160
                              panel_marshal_BOOLEAN__VOID,
 
4161
                              G_TYPE_BOOLEAN,
 
4162
                              0);
 
4163
 
 
4164
        toplevel_signals [BEGIN_MOVE_SIGNAL] =
 
4165
                g_signal_new ("begin-move",
 
4166
                              G_TYPE_FROM_CLASS (gobject_class),
 
4167
                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
4168
                              G_STRUCT_OFFSET (PanelToplevelClass, begin_move),
 
4169
                              NULL,
 
4170
                              NULL,
 
4171
                              panel_marshal_BOOLEAN__VOID,
 
4172
                              G_TYPE_BOOLEAN,
 
4173
                              0);
 
4174
 
 
4175
        toplevel_signals [BEGIN_RESIZE_SIGNAL] =
 
4176
                g_signal_new ("begin-resize",
 
4177
                              G_TYPE_FROM_CLASS (gobject_class),
 
4178
                              G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
 
4179
                              G_STRUCT_OFFSET (PanelToplevelClass, begin_resize),
 
4180
                              NULL,
 
4181
                              NULL,
 
4182
                              panel_marshal_BOOLEAN__VOID,
 
4183
                              G_TYPE_BOOLEAN,
 
4184
                              0);
 
4185
 
 
4186
        gtk_binding_entry_add_signal (binding_set, GDK_KEY_F10, GDK_CONTROL_MASK,
 
4187
                                     "popup_panel_menu", 0);
 
4188
 
 
4189
        panel_bindings_set_entries (binding_set);
 
4190
}
 
4191
 
 
4192
static void
 
4193
panel_toplevel_setup_widgets (PanelToplevel *toplevel)
 
4194
{
 
4195
        GtkWidget *container;
 
4196
 
 
4197
        toplevel->priv->table = gtk_table_new (3, 3, FALSE);
 
4198
 
 
4199
        toplevel->priv->hide_button_top =
 
4200
                panel_toplevel_add_hide_button (toplevel, GTK_ARROW_UP,    1, 2, 0, 1);
 
4201
 
 
4202
        toplevel->priv->hide_button_bottom =
 
4203
                panel_toplevel_add_hide_button (toplevel, GTK_ARROW_DOWN,  1, 2, 2, 3);
 
4204
 
 
4205
        toplevel->priv->hide_button_left =
 
4206
                panel_toplevel_add_hide_button (toplevel, GTK_ARROW_LEFT,  0, 1, 1, 2);
 
4207
 
 
4208
        toplevel->priv->hide_button_right =
 
4209
                panel_toplevel_add_hide_button (toplevel, GTK_ARROW_RIGHT, 2, 3, 1, 2);
 
4210
 
 
4211
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK) {
 
4212
                gtk_widget_show (toplevel->priv->hide_button_left);
 
4213
                gtk_widget_show (toplevel->priv->hide_button_right);
 
4214
        } else {
 
4215
                gtk_widget_show (toplevel->priv->hide_button_top);
 
4216
                gtk_widget_show (toplevel->priv->hide_button_bottom);
 
4217
        }
 
4218
 
 
4219
        toplevel->priv->inner_frame = g_object_new (PANEL_TYPE_FRAME, NULL);
 
4220
 
 
4221
        gtk_table_attach (GTK_TABLE (toplevel->priv->table),
 
4222
                          GTK_WIDGET (toplevel->priv->inner_frame),
 
4223
                          1, 2,
 
4224
                          1, 2,
 
4225
                          GTK_FILL | GTK_EXPAND | GTK_SHRINK,
 
4226
                          GTK_FILL | GTK_EXPAND | GTK_SHRINK,
 
4227
                          0, 0);
 
4228
        gtk_widget_show (GTK_WIDGET (toplevel->priv->inner_frame));
 
4229
 
 
4230
        container = panel_widget_new (toplevel,
 
4231
                                      !toplevel->priv->expand,
 
4232
                                      toplevel->priv->orientation & PANEL_HORIZONTAL_MASK ?
 
4233
                                                GTK_ORIENTATION_HORIZONTAL :
 
4234
                                                GTK_ORIENTATION_VERTICAL,       
 
4235
                                      toplevel->priv->size);
 
4236
 
 
4237
        toplevel->priv->panel_widget = PANEL_WIDGET (container);
 
4238
 
 
4239
        gtk_container_add (GTK_CONTAINER (toplevel->priv->inner_frame), container);
 
4240
        gtk_widget_show (container);
 
4241
 
 
4242
        gtk_container_add (GTK_CONTAINER (toplevel), toplevel->priv->table);
 
4243
        gtk_widget_show (toplevel->priv->table);
 
4244
 
 
4245
}
 
4246
 
 
4247
static void
 
4248
panel_toplevel_init (PanelToplevel *toplevel)
 
4249
{
 
4250
        GtkStyleContext *context;
 
4251
 
 
4252
        toplevel->priv = PANEL_TOPLEVEL_GET_PRIVATE (toplevel);
 
4253
 
 
4254
        toplevel->priv->toplevel_id      = NULL;
 
4255
 
 
4256
        toplevel->priv->settings_path    = NULL;
 
4257
        toplevel->priv->settings         = NULL;
 
4258
        toplevel->priv->delayed_settings = NULL;
 
4259
        toplevel->priv->apply_delayed_id = 0;
 
4260
 
 
4261
        toplevel->priv->expand          = TRUE;
 
4262
        toplevel->priv->orientation     = PANEL_ORIENTATION_BOTTOM;
 
4263
        toplevel->priv->size            = DEFAULT_SIZE;
 
4264
        toplevel->priv->x               = 0;
 
4265
        toplevel->priv->y               = 0;
 
4266
        toplevel->priv->x_right         = -1;
 
4267
        toplevel->priv->y_bottom        = -1;
 
4268
        toplevel->priv->monitor         = 0;
 
4269
        toplevel->priv->configured_monitor = -1;
 
4270
        toplevel->priv->hide_delay      = DEFAULT_HIDE_DELAY;
 
4271
        toplevel->priv->unhide_delay    = DEFAULT_UNHIDE_DELAY;
 
4272
        toplevel->priv->auto_hide_size  = DEFAULT_AUTO_HIDE_SIZE;
 
4273
        toplevel->priv->animation_speed = PANEL_ANIMATION_FAST;
 
4274
 
 
4275
        toplevel->priv->snap_tolerance  = DEFAULT_DND_THRESHOLD * SNAP_TOLERANCE_FACTOR;
 
4276
        toplevel->priv->gtk_settings    = NULL;
 
4277
 
 
4278
        toplevel->priv->state = PANEL_STATE_NORMAL;
 
4279
 
 
4280
        toplevel->priv->name        = NULL;
 
4281
        toplevel->priv->description = NULL;
 
4282
 
 
4283
        toplevel->priv->hide_timeout   = 0;
 
4284
        toplevel->priv->unhide_timeout = 0;
 
4285
 
 
4286
        toplevel->priv->geometry.x      = -1;
 
4287
        toplevel->priv->geometry.y      = -1;
 
4288
        toplevel->priv->geometry.width  = -1;
 
4289
        toplevel->priv->geometry.height = -1;
 
4290
 
 
4291
        toplevel->priv->original_width  = -1;
 
4292
        toplevel->priv->original_height = -1;
 
4293
 
 
4294
        toplevel->priv->grab_op = PANEL_GRAB_OP_NONE;
 
4295
 
 
4296
        toplevel->priv->drag_offset_x = 0;
 
4297
        toplevel->priv->drag_offset_y = 0;
 
4298
 
 
4299
        toplevel->priv->animation_end_x              = 0;
 
4300
        toplevel->priv->animation_end_y              = 0;
 
4301
        toplevel->priv->animation_end_width          = 0;
 
4302
        toplevel->priv->animation_end_height         = 0;
 
4303
        toplevel->priv->animation_start_time.tv_sec  = 0;
 
4304
        toplevel->priv->animation_start_time.tv_usec = 0;
 
4305
        toplevel->priv->animation_end_time.tv_sec    = 0;
 
4306
        toplevel->priv->animation_end_time.tv_usec   = 0;
 
4307
        toplevel->priv->animation_timeout            = 0;
 
4308
 
 
4309
        toplevel->priv->panel_widget       = NULL;
 
4310
        toplevel->priv->inner_frame        = NULL;
 
4311
        toplevel->priv->table              = NULL;
 
4312
        toplevel->priv->hide_button_top    = NULL;
 
4313
        toplevel->priv->hide_button_bottom = NULL;
 
4314
        toplevel->priv->hide_button_left   = NULL;
 
4315
        toplevel->priv->hide_button_right  = NULL;
 
4316
 
 
4317
        toplevel->priv->n_autohide_disablers = 0;
 
4318
 
 
4319
        toplevel->priv->auto_hide         = FALSE;
 
4320
        toplevel->priv->buttons_enabled   = TRUE;
 
4321
        toplevel->priv->arrows_enabled    = TRUE;
 
4322
        toplevel->priv->x_centered        = FALSE;
 
4323
        toplevel->priv->y_centered        = FALSE;
 
4324
        toplevel->priv->animating         = FALSE;
 
4325
        toplevel->priv->grab_is_keyboard  = FALSE;
 
4326
        toplevel->priv->position_centered = FALSE;
 
4327
        toplevel->priv->updated_geometry_initial = FALSE;
 
4328
        toplevel->priv->initial_animation_done   = FALSE;
 
4329
 
 
4330
        gtk_widget_add_events (GTK_WIDGET (toplevel),
 
4331
                               GDK_BUTTON_PRESS_MASK |
 
4332
                               GDK_BUTTON_RELEASE_MASK |
 
4333
                               GDK_POINTER_MOTION_MASK |
 
4334
                               GDK_ENTER_NOTIFY_MASK |
 
4335
                               GDK_LEAVE_NOTIFY_MASK);
 
4336
 
 
4337
        panel_toplevel_setup_widgets (toplevel);
 
4338
        panel_toplevel_update_description (toplevel);
 
4339
        panel_toplevel_update_gtk_settings (toplevel);
 
4340
        
 
4341
        toplevel_list = g_slist_prepend (toplevel_list, toplevel);
 
4342
 
 
4343
        /* Prevent the window from being deleted via Alt+F4 by accident.  This
 
4344
         * happens with "alternative" window managers such as Sawfish or XFWM4.
 
4345
         */
 
4346
        g_signal_connect (GTK_WIDGET (toplevel),
 
4347
                          "delete-event",
 
4348
                          G_CALLBACK (gtk_true),
 
4349
                          NULL);
 
4350
 
 
4351
        /* We don't want a resize grip on the panel */
 
4352
        gtk_window_set_has_resize_grip (GTK_WINDOW (toplevel), FALSE);
 
4353
 
 
4354
        context = gtk_widget_get_style_context (GTK_WIDGET (toplevel));
 
4355
        gtk_style_context_add_class (context, GTK_STYLE_CLASS_HORIZONTAL);
 
4356
}
 
4357
 
 
4358
PanelWidget *
 
4359
panel_toplevel_get_panel_widget (PanelToplevel *toplevel)
 
4360
{
 
4361
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
 
4362
 
 
4363
        return toplevel->priv->panel_widget;
 
4364
}
 
4365
 
 
4366
static gboolean
 
4367
panel_toplevel_position_is_writable (PanelToplevel *toplevel)
 
4368
{
 
4369
        if (panel_lockdown_get_panels_locked_down_s () ||
 
4370
            !(g_settings_is_writable (toplevel->priv->settings,
 
4371
                                      PANEL_TOPLEVEL_SCREEN_KEY) &&
 
4372
              g_settings_is_writable (toplevel->priv->settings,
 
4373
                                      PANEL_TOPLEVEL_MONITOR_KEY) &&
 
4374
              g_settings_is_writable (toplevel->priv->settings,
 
4375
                                      PANEL_TOPLEVEL_ORIENTATION_KEY)))
 
4376
                return FALSE;
 
4377
 
 
4378
        /* For expanded panels we don't really have to check x and y */
 
4379
        if (panel_toplevel_get_expand (toplevel))
 
4380
                return TRUE;
 
4381
 
 
4382
        return (g_settings_is_writable (toplevel->priv->settings,
 
4383
                                        PANEL_TOPLEVEL_X_KEY) &&
 
4384
                g_settings_is_writable (toplevel->priv->settings,
 
4385
                                        PANEL_TOPLEVEL_Y_KEY) &&
 
4386
                g_settings_is_writable (toplevel->priv->settings,
 
4387
                                        PANEL_TOPLEVEL_X_RIGHT_KEY) &&
 
4388
                g_settings_is_writable (toplevel->priv->settings,
 
4389
                                        PANEL_TOPLEVEL_Y_BOTTOM_KEY) &&
 
4390
                g_settings_is_writable (toplevel->priv->settings,
 
4391
                                        PANEL_TOPLEVEL_X_CENTERED_KEY) &&
 
4392
                g_settings_is_writable (toplevel->priv->settings,
 
4393
                                        PANEL_TOPLEVEL_Y_CENTERED_KEY));
 
4394
}
 
4395
 
 
4396
static gboolean
 
4397
panel_toplevel_apply_delayed_settings (PanelToplevel *toplevel)
 
4398
{
 
4399
        g_settings_apply (toplevel->priv->delayed_settings);
 
4400
 
 
4401
        toplevel->priv->apply_delayed_id = 0;
 
4402
 
 
4403
        return FALSE;
 
4404
}
 
4405
 
 
4406
static void
 
4407
panel_toplevel_apply_delayed_settings_queue (PanelToplevel *toplevel)
 
4408
{
 
4409
        if (toplevel->priv->apply_delayed_id != 0)
 
4410
                return;
 
4411
 
 
4412
        toplevel->priv->apply_delayed_id = g_timeout_add (500,
 
4413
                                                          (GSourceFunc) panel_toplevel_apply_delayed_settings,
 
4414
                                                          toplevel);
 
4415
}
 
4416
 
 
4417
static gboolean
 
4418
panel_toplevel_settings_bind_get_screen (GValue   *value,
 
4419
                                         GVariant *variant,
 
4420
                                         gpointer  user_data)
 
4421
{
 
4422
        PanelToplevel *toplevel = PANEL_TOPLEVEL (user_data);
 
4423
        GdkDisplay    *display;
 
4424
        GdkScreen     *screen;
 
4425
        int            screen_n;
 
4426
 
 
4427
        display = gdk_display_get_default ();
 
4428
        screen_n = g_variant_get_int32 (variant);
 
4429
 
 
4430
        if (screen_n < 0 || screen_n >= gdk_display_get_n_screens (display)) {
 
4431
                /* Trigger an event so that the gsettings key gets updated, to
 
4432
                 * to set the key back to an actual available screen so it will
 
4433
                 * get loaded on next startup. */
 
4434
                g_object_notify (G_OBJECT (toplevel), "screen");
 
4435
                return FALSE;
 
4436
        }
 
4437
 
 
4438
        screen = gdk_display_get_screen (display, screen_n);
 
4439
 
 
4440
        if (screen != NULL)
 
4441
                g_value_set_object (value, screen);
 
4442
 
 
4443
        return (screen != NULL);
 
4444
}
 
4445
 
 
4446
static GVariant *
 
4447
panel_toplevel_settings_bind_set_screen (const GValue       *value,
 
4448
                                         const GVariantType *expected_type,
 
4449
                                         gpointer            user_data)
 
4450
{
 
4451
        GdkScreen *screen = g_value_get_object (value);
 
4452
 
 
4453
        if (!screen || !GDK_IS_SCREEN (screen))
 
4454
                screen = gdk_screen_get_default ();
 
4455
 
 
4456
        return g_variant_new ("i", gdk_screen_get_number (screen));
 
4457
}
 
4458
 
 
4459
static void
 
4460
panel_toplevel_bind_gsettings (PanelToplevel *toplevel)
 
4461
{
 
4462
        /* Delayed settings: the ones related to the position */
 
4463
 
 
4464
        g_settings_bind (toplevel->priv->delayed_settings,
 
4465
                         PANEL_TOPLEVEL_MONITOR_KEY,
 
4466
                         toplevel,
 
4467
                         "monitor",
 
4468
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4469
 
 
4470
        g_settings_bind (toplevel->priv->delayed_settings,
 
4471
                         PANEL_TOPLEVEL_SIZE_KEY,
 
4472
                         toplevel,
 
4473
                         "size",
 
4474
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4475
 
 
4476
        g_settings_bind (toplevel->priv->delayed_settings,
 
4477
                         PANEL_TOPLEVEL_ORIENTATION_KEY,
 
4478
                         toplevel,
 
4479
                         "orientation",
 
4480
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4481
 
 
4482
        g_settings_bind (toplevel->priv->delayed_settings,
 
4483
                         PANEL_TOPLEVEL_X_KEY,
 
4484
                         toplevel,
 
4485
                         "x",
 
4486
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4487
 
 
4488
        g_settings_bind (toplevel->priv->delayed_settings,
 
4489
                         PANEL_TOPLEVEL_X_RIGHT_KEY,
 
4490
                         toplevel,
 
4491
                         "x-right",
 
4492
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4493
 
 
4494
        g_settings_bind (toplevel->priv->delayed_settings,
 
4495
                         PANEL_TOPLEVEL_X_CENTERED_KEY,
 
4496
                         toplevel,
 
4497
                         "x-centered",
 
4498
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4499
 
 
4500
        g_settings_bind (toplevel->priv->delayed_settings,
 
4501
                         PANEL_TOPLEVEL_Y_KEY,
 
4502
                         toplevel,
 
4503
                         "y",
 
4504
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4505
 
 
4506
        g_settings_bind (toplevel->priv->delayed_settings,
 
4507
                         PANEL_TOPLEVEL_Y_BOTTOM_KEY,
 
4508
                         toplevel,
 
4509
                         "y-bottom",
 
4510
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4511
 
 
4512
        g_settings_bind (toplevel->priv->delayed_settings,
 
4513
                         PANEL_TOPLEVEL_Y_CENTERED_KEY,
 
4514
                         toplevel,
 
4515
                         "y-centered",
 
4516
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4517
 
 
4518
        /* Normal settings */
 
4519
 
 
4520
        g_settings_bind_with_mapping (toplevel->priv->settings,
 
4521
                                      PANEL_TOPLEVEL_SCREEN_KEY,
 
4522
                                      toplevel,
 
4523
                                      "screen",
 
4524
                                      G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY,
 
4525
                                      panel_toplevel_settings_bind_get_screen,
 
4526
                                      panel_toplevel_settings_bind_set_screen,
 
4527
                                      toplevel, NULL);
 
4528
 
 
4529
        g_settings_bind (toplevel->priv->settings,
 
4530
                         PANEL_TOPLEVEL_NAME_KEY,
 
4531
                         toplevel,
 
4532
                         "name",
 
4533
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4534
 
 
4535
        g_settings_bind (toplevel->priv->settings,
 
4536
                         PANEL_TOPLEVEL_EXPAND_KEY,
 
4537
                         toplevel,
 
4538
                         "expand",
 
4539
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4540
 
 
4541
        g_settings_bind (toplevel->priv->settings,
 
4542
                         PANEL_TOPLEVEL_AUTO_HIDE_KEY,
 
4543
                         toplevel,
 
4544
                         "auto-hide",
 
4545
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4546
 
 
4547
        g_settings_bind (toplevel->priv->settings,
 
4548
                         PANEL_TOPLEVEL_HIDE_DELAY_KEY,
 
4549
                         toplevel,
 
4550
                         "hide-delay",
 
4551
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4552
 
 
4553
        g_settings_bind (toplevel->priv->settings,
 
4554
                         PANEL_TOPLEVEL_UNHIDE_DELAY_KEY,
 
4555
                         toplevel,
 
4556
                         "unhide-delay",
 
4557
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4558
 
 
4559
        g_settings_bind (toplevel->priv->settings,
 
4560
                         PANEL_TOPLEVEL_AUTO_HIDE_SIZE_KEY,
 
4561
                         toplevel,
 
4562
                         "auto-hide-size",
 
4563
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4564
 
 
4565
        g_settings_bind (toplevel->priv->settings,
 
4566
                         PANEL_TOPLEVEL_ANIMATION_SPEED_KEY,
 
4567
                         toplevel,
 
4568
                         "animation-speed",
 
4569
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4570
 
 
4571
        g_settings_bind (toplevel->priv->settings,
 
4572
                         PANEL_TOPLEVEL_ENABLE_BUTTONS_KEY,
 
4573
                         toplevel,
 
4574
                         "buttons-enabled",
 
4575
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4576
 
 
4577
        g_settings_bind (toplevel->priv->settings,
 
4578
                         PANEL_TOPLEVEL_ENABLE_ARROWS_KEY,
 
4579
                         toplevel,
 
4580
                         "arrows-enabled",
 
4581
                         G_SETTINGS_BIND_DEFAULT|G_SETTINGS_BIND_NO_SENSITIVITY);
 
4582
}
 
4583
 
 
4584
static void
 
4585
panel_toplevel_set_toplevel_id (PanelToplevel *toplevel,
 
4586
                                const char    *toplevel_id)
 
4587
{
 
4588
        g_assert (toplevel->priv->toplevel_id == NULL);
 
4589
 
 
4590
        toplevel->priv->toplevel_id = g_strdup (toplevel_id);
 
4591
}
 
4592
 
 
4593
const char *
 
4594
panel_toplevel_get_id (PanelToplevel *toplevel)
 
4595
{
 
4596
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
 
4597
 
 
4598
        return toplevel->priv->toplevel_id;
 
4599
}
 
4600
 
 
4601
static void
 
4602
panel_toplevel_set_settings_path (PanelToplevel *toplevel,
 
4603
                                  const char    *settings_path)
 
4604
{
 
4605
        GSettings *settings_background;
 
4606
 
 
4607
        g_assert (toplevel->priv->settings_path == NULL);
 
4608
        g_assert (toplevel->priv->settings == NULL);
 
4609
        g_assert (toplevel->priv->delayed_settings == NULL);
 
4610
 
 
4611
        toplevel->priv->settings_path = g_strdup (settings_path);
 
4612
        toplevel->priv->settings = g_settings_new_with_path (PANEL_TOPLEVEL_SCHEMA,
 
4613
                                                             settings_path);
 
4614
        toplevel->priv->delayed_settings = g_settings_new_with_path (PANEL_TOPLEVEL_SCHEMA,
 
4615
                                                                     settings_path);
 
4616
        g_settings_delay (toplevel->priv->delayed_settings);
 
4617
 
 
4618
        settings_background = g_settings_get_child (toplevel->priv->settings,
 
4619
                                                    PANEL_BACKGROUND_SCHEMA_CHILD);
 
4620
        /* FIXME: ideally, move this inside panel-widget.c since we're not
 
4621
         * supposed to know about the backgrounds here */
 
4622
        panel_background_settings_init (&toplevel->priv->panel_widget->background,
 
4623
                                        settings_background);
 
4624
        g_object_unref (settings_background);
 
4625
}
 
4626
 
 
4627
static void
 
4628
panel_toplevel_update_name (PanelToplevel *toplevel)
 
4629
{
 
4630
        char *title;
 
4631
 
 
4632
        g_assert (toplevel->priv->description != NULL);
 
4633
 
 
4634
        title = toplevel->priv->name ? toplevel->priv->name : toplevel->priv->description;
 
4635
 
 
4636
        gtk_window_set_title (GTK_WINDOW (toplevel), title);
 
4637
 
 
4638
        panel_a11y_set_atk_name_desc (
 
4639
                GTK_WIDGET (toplevel->priv->panel_widget),
 
4640
                title, toplevel->priv->description);
 
4641
}
 
4642
 
 
4643
void
 
4644
panel_toplevel_set_name (PanelToplevel *toplevel,
 
4645
                         const char    *name)
 
4646
{
 
4647
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
4648
 
 
4649
        if (!toplevel->priv->name && (!name || !name [0]))
 
4650
                return;
 
4651
 
 
4652
        if (toplevel->priv->name && name && name [0] &&
 
4653
            !strcmp (toplevel->priv->name, name))
 
4654
                return;
 
4655
 
 
4656
        if (toplevel->priv->name)
 
4657
                g_free (toplevel->priv->name);
 
4658
        toplevel->priv->name = NULL;
 
4659
 
 
4660
        if (name && name [0])
 
4661
                toplevel->priv->name = g_strdup (name);
 
4662
 
 
4663
        panel_toplevel_update_name (toplevel);
 
4664
 
 
4665
        g_object_notify (G_OBJECT (toplevel), "name");
 
4666
}
 
4667
 
 
4668
const char *
 
4669
panel_toplevel_get_name (PanelToplevel *toplevel)
 
4670
{
 
4671
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
 
4672
 
 
4673
        return toplevel->priv->name;
 
4674
}
 
4675
 
 
4676
const char *
 
4677
panel_toplevel_get_description (PanelToplevel *toplevel)
 
4678
{
 
4679
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), NULL);
 
4680
 
 
4681
        return toplevel->priv->description;
 
4682
}
 
4683
 
 
4684
void
 
4685
panel_toplevel_set_expand (PanelToplevel *toplevel,
 
4686
                           gboolean       expand)
 
4687
{
 
4688
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
4689
 
 
4690
        expand = expand != FALSE;
 
4691
 
 
4692
        if (toplevel->priv->expand == expand)
 
4693
                return;
 
4694
 
 
4695
        toplevel->priv->expand = expand;
 
4696
 
 
4697
        if (!toplevel->priv->expand &&
 
4698
            toplevel->priv->updated_geometry_initial) {
 
4699
                switch (toplevel->priv->orientation) {
 
4700
                case PANEL_ORIENTATION_TOP:
 
4701
                        panel_toplevel_set_x (toplevel, 0, -1, TRUE);
 
4702
                        break;
 
4703
                case PANEL_ORIENTATION_BOTTOM:
 
4704
                        panel_toplevel_set_x (toplevel, 0, 0, TRUE);
 
4705
                        break;
 
4706
                case PANEL_ORIENTATION_LEFT:
 
4707
                        panel_toplevel_set_y (toplevel, 0, -1, TRUE);
 
4708
                        break;
 
4709
                case PANEL_ORIENTATION_RIGHT:
 
4710
                        panel_toplevel_set_y (toplevel, 0, 0, TRUE);
 
4711
                        break;
 
4712
                default:
 
4713
                        g_assert_not_reached ();
 
4714
                        break;
 
4715
                }
 
4716
        }
 
4717
 
 
4718
        gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
4719
 
 
4720
        panel_widget_set_packed (toplevel->priv->panel_widget, !toplevel->priv->expand);
 
4721
 
 
4722
        g_object_notify (G_OBJECT (toplevel), "expand");
 
4723
}
 
4724
 
 
4725
gboolean
 
4726
panel_toplevel_get_expand (PanelToplevel *toplevel)
 
4727
{
 
4728
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), TRUE);
 
4729
 
 
4730
        return toplevel->priv->expand;
 
4731
}
 
4732
 
 
4733
gboolean
 
4734
panel_toplevel_get_is_floating (PanelToplevel *toplevel)
 
4735
{
 
4736
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), TRUE);
 
4737
 
 
4738
        return toplevel->priv->floating;
 
4739
}
 
4740
 
 
4741
void
 
4742
panel_toplevel_set_orientation (PanelToplevel    *toplevel,
 
4743
                                PanelOrientation  orientation)
 
4744
{
 
4745
        gboolean   rotate;
 
4746
        int        monitor_width;
 
4747
        int        monitor_height;
 
4748
        GtkStyleContext *context;
 
4749
 
 
4750
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
4751
 
 
4752
        if (toplevel->priv->orientation == orientation)
 
4753
                return;
 
4754
 
 
4755
        g_object_freeze_notify (G_OBJECT (toplevel));
 
4756
 
 
4757
        panel_toplevel_get_monitor_geometry (
 
4758
                toplevel, NULL, NULL, &monitor_width, &monitor_height);
 
4759
 
 
4760
        /* Un-snap from center if no longer along screen edge */
 
4761
        if (toplevel->priv->x_centered &&
 
4762
            (orientation & PANEL_VERTICAL_MASK)) {
 
4763
                toplevel->priv->x_centered = FALSE;
 
4764
                toplevel->priv->x = (monitor_width - toplevel->priv->geometry.width) / 2;
 
4765
                g_object_notify (G_OBJECT (toplevel), "x");
 
4766
                g_object_notify (G_OBJECT (toplevel), "x-centered");
 
4767
 
 
4768
                if (toplevel->priv->x_right != -1) {
 
4769
                        toplevel->priv->x_right = -1;
 
4770
                        g_object_notify (G_OBJECT (toplevel), "x-right");
 
4771
                }
 
4772
        }
 
4773
 
 
4774
        if (toplevel->priv->y_centered &&
 
4775
            (orientation & PANEL_HORIZONTAL_MASK)) {
 
4776
                toplevel->priv->y_centered = FALSE;
 
4777
                toplevel->priv->y = (monitor_height - toplevel->priv->geometry.height) / 2;
 
4778
                g_object_notify (G_OBJECT (toplevel), "y");
 
4779
                g_object_notify (G_OBJECT (toplevel), "y-centered");
 
4780
 
 
4781
                if (toplevel->priv->y_bottom != -1) {
 
4782
                        toplevel->priv->y_bottom = -1;
 
4783
                        g_object_notify (G_OBJECT (toplevel), "y-bottom");
 
4784
                }
 
4785
        }
 
4786
 
 
4787
        rotate = FALSE;
 
4788
        if ((orientation & PANEL_HORIZONTAL_MASK) &&
 
4789
            (toplevel->priv->orientation & PANEL_VERTICAL_MASK))
 
4790
                rotate = TRUE;
 
4791
        else if ((orientation & PANEL_VERTICAL_MASK) &&
 
4792
                 (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK))
 
4793
                rotate = TRUE;
 
4794
 
 
4795
        /* rotate around the center */
 
4796
        if (rotate && !toplevel->priv->position_centered && !toplevel->priv->expand &&
 
4797
            toplevel->priv->updated_geometry_initial) {
 
4798
                toplevel->priv->position_centered = TRUE;
 
4799
 
 
4800
                /* x, y temporary refer to the panel center, so we don't care
 
4801
                 * about x_right, y_bottom. Those will get updated in
 
4802
                 * panel_toplevel_update_position() accordingly. */
 
4803
                if (!toplevel->priv->x_centered) {
 
4804
                        toplevel->priv->x += toplevel->priv->geometry.width  / 2;
 
4805
                        g_object_notify (G_OBJECT (toplevel), "x");
 
4806
                }
 
4807
 
 
4808
                if (!toplevel->priv->y_centered) {
 
4809
                        toplevel->priv->y += toplevel->priv->geometry.height / 2;
 
4810
                        g_object_notify (G_OBJECT (toplevel), "y");
 
4811
                }
 
4812
 
 
4813
        }
 
4814
 
 
4815
        toplevel->priv->orientation = orientation;
 
4816
 
 
4817
        context = gtk_widget_get_style_context (GTK_WIDGET (toplevel));
 
4818
        if (orientation & PANEL_HORIZONTAL_MASK) {
 
4819
                gtk_style_context_add_class (context, GTK_STYLE_CLASS_HORIZONTAL);
 
4820
                gtk_style_context_remove_class (context, GTK_STYLE_CLASS_VERTICAL);
 
4821
        } else {
 
4822
                gtk_style_context_add_class (context, GTK_STYLE_CLASS_VERTICAL);
 
4823
                gtk_style_context_remove_class (context, GTK_STYLE_CLASS_HORIZONTAL);
 
4824
        }
 
4825
        gtk_widget_reset_style (GTK_WIDGET (toplevel));
 
4826
 
 
4827
        panel_toplevel_update_hide_buttons (toplevel);
 
4828
 
 
4829
        panel_widget_set_orientation (  
 
4830
                toplevel->priv->panel_widget,
 
4831
                toplevel->priv->orientation & PANEL_HORIZONTAL_MASK ?
 
4832
                                        GTK_ORIENTATION_HORIZONTAL :
 
4833
                                        GTK_ORIENTATION_VERTICAL);
 
4834
 
 
4835
        switch (toplevel->priv->state) {
 
4836
        case PANEL_STATE_HIDDEN_UP:
 
4837
                if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)
 
4838
                        toplevel->priv->state = PANEL_STATE_HIDDEN_LEFT;
 
4839
                break;
 
4840
        case PANEL_STATE_HIDDEN_DOWN:
 
4841
                if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)
 
4842
                        toplevel->priv->state = PANEL_STATE_HIDDEN_RIGHT;
 
4843
                break;
 
4844
        case PANEL_STATE_HIDDEN_LEFT:
 
4845
                if (toplevel->priv->orientation & PANEL_VERTICAL_MASK)
 
4846
                        toplevel->priv->state = PANEL_STATE_HIDDEN_UP;
 
4847
                break;
 
4848
        case PANEL_STATE_HIDDEN_RIGHT:
 
4849
                if (toplevel->priv->orientation & PANEL_VERTICAL_MASK)
 
4850
                        toplevel->priv->state = PANEL_STATE_HIDDEN_DOWN;
 
4851
                break;
 
4852
        default:
 
4853
                break;
 
4854
        }
 
4855
 
 
4856
        gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
4857
 
 
4858
        panel_toplevel_apply_delayed_settings_queue (toplevel);
 
4859
        g_object_notify (G_OBJECT (toplevel), "orientation");
 
4860
 
 
4861
        g_object_thaw_notify (G_OBJECT (toplevel));
 
4862
}
 
4863
 
 
4864
PanelOrientation
 
4865
panel_toplevel_get_orientation (PanelToplevel *toplevel)
 
4866
{
 
4867
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), GTK_ORIENTATION_HORIZONTAL);
 
4868
 
 
4869
        return toplevel->priv->orientation;
 
4870
}
 
4871
 
 
4872
void
 
4873
panel_toplevel_set_size (PanelToplevel *toplevel,
 
4874
                         int            size)
 
4875
{
 
4876
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
4877
        g_return_if_fail (size >= 0);
 
4878
 
 
4879
        if (toplevel->priv->size == size)
 
4880
                return;
 
4881
 
 
4882
        toplevel->priv->size = size;
 
4883
 
 
4884
        panel_widget_set_size (toplevel->priv->panel_widget, toplevel->priv->size);
 
4885
 
 
4886
        gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
4887
 
 
4888
        panel_toplevel_apply_delayed_settings_queue (toplevel);
 
4889
        g_object_notify (G_OBJECT (toplevel), "size");
 
4890
}
 
4891
 
 
4892
int
 
4893
panel_toplevel_get_size (PanelToplevel *toplevel)
 
4894
{
 
4895
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), DEFAULT_SIZE);
 
4896
 
 
4897
        return toplevel->priv->size;
 
4898
}
 
4899
 
 
4900
void
 
4901
panel_toplevel_set_auto_hide_size (PanelToplevel *toplevel,
 
4902
                                   int            auto_hide_size)
 
4903
{
 
4904
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
4905
 
 
4906
        if (toplevel->priv->auto_hide_size == auto_hide_size)
 
4907
                return;
 
4908
 
 
4909
        toplevel->priv->auto_hide_size = auto_hide_size;
 
4910
 
 
4911
        if (toplevel->priv->state == PANEL_STATE_AUTO_HIDDEN) {
 
4912
                if (panel_toplevel_update_struts (toplevel, FALSE)) {
 
4913
                        if (toplevel->priv->animate) {
 
4914
                                panel_toplevel_unhide (toplevel);
 
4915
                                panel_toplevel_hide (toplevel, TRUE, -1);
 
4916
                        } else
 
4917
                                gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
4918
                }
 
4919
        }
 
4920
 
 
4921
        g_object_notify (G_OBJECT (toplevel), "auto-hide-size");
 
4922
}
 
4923
 
 
4924
int
 
4925
panel_toplevel_get_auto_hide_size (PanelToplevel *toplevel)
 
4926
{
 
4927
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), DEFAULT_AUTO_HIDE_SIZE);
 
4928
 
 
4929
        return toplevel->priv->auto_hide_size;
 
4930
}
 
4931
 
 
4932
void
 
4933
panel_toplevel_set_x (PanelToplevel *toplevel,
 
4934
                      int            x,
 
4935
                      int            x_right,
 
4936
                      gboolean       x_centered)
 
4937
{
 
4938
        gboolean changed = FALSE;
 
4939
 
 
4940
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
4941
 
 
4942
        x_centered = x_centered != FALSE;
 
4943
 
 
4944
        g_object_freeze_notify (G_OBJECT (toplevel));
 
4945
 
 
4946
        if (toplevel->priv->x != x) {
 
4947
                toplevel->priv->x = x;
 
4948
                changed = TRUE;
 
4949
                g_object_notify (G_OBJECT (toplevel), "x");
 
4950
        }
 
4951
 
 
4952
        if (toplevel->priv->x_right != x_right) {
 
4953
                toplevel->priv->x_right = x_right;
 
4954
                changed = TRUE;
 
4955
                g_object_notify (G_OBJECT (toplevel), "x-right");
 
4956
        }
 
4957
 
 
4958
        if (toplevel->priv->x_centered != x_centered) {
 
4959
                toplevel->priv->x_centered = x_centered;
 
4960
                changed = TRUE;
 
4961
                g_object_notify (G_OBJECT (toplevel), "x-centered");
 
4962
        }
 
4963
 
 
4964
        if (changed) {
 
4965
                panel_toplevel_apply_delayed_settings_queue (toplevel);
 
4966
                gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
4967
        }
 
4968
 
 
4969
        g_object_thaw_notify (G_OBJECT (toplevel));
 
4970
}
 
4971
 
 
4972
void
 
4973
panel_toplevel_set_y (PanelToplevel *toplevel,
 
4974
                      int            y,
 
4975
                      int            y_bottom,
 
4976
                      gboolean       y_centered)
 
4977
{
 
4978
        gboolean changed = FALSE;
 
4979
 
 
4980
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
4981
 
 
4982
        y_centered = y_centered != FALSE;
 
4983
 
 
4984
        g_object_freeze_notify (G_OBJECT (toplevel));
 
4985
 
 
4986
        if (toplevel->priv->y != y) {
 
4987
                toplevel->priv->y = y;
 
4988
                changed = TRUE;
 
4989
                g_object_notify (G_OBJECT (toplevel), "y");
 
4990
        }
 
4991
 
 
4992
        if (toplevel->priv->y_bottom != y_bottom) {
 
4993
                toplevel->priv->y_bottom = y_bottom;
 
4994
                changed = TRUE;
 
4995
                g_object_notify (G_OBJECT (toplevel), "y-bottom");
 
4996
        }
 
4997
 
 
4998
        if (toplevel->priv->y_centered != y_centered) {
 
4999
                toplevel->priv->y_centered = y_centered;
 
5000
                changed = TRUE;
 
5001
                g_object_notify (G_OBJECT (toplevel), "y-centered");
 
5002
        }
 
5003
 
 
5004
        if (changed) {
 
5005
                panel_toplevel_apply_delayed_settings_queue (toplevel);
 
5006
                gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
5007
        }
 
5008
 
 
5009
        g_object_thaw_notify (G_OBJECT (toplevel));
 
5010
}
 
5011
 
 
5012
void
 
5013
panel_toplevel_get_position (PanelToplevel *toplevel,
 
5014
                             int           *x,
 
5015
                             int           *x_right,
 
5016
                             int           *y,
 
5017
                             int           *y_bottom)
 
5018
{
 
5019
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5020
 
 
5021
        if (x)
 
5022
                *x = toplevel->priv->x;
 
5023
 
 
5024
        if (y)
 
5025
                *y = toplevel->priv->y;
 
5026
 
 
5027
        if (x_right)
 
5028
                *x_right = toplevel->priv->x_right;
 
5029
 
 
5030
        if (y_bottom)
 
5031
                *y_bottom = toplevel->priv->y_bottom;
 
5032
}
 
5033
 
 
5034
gboolean
 
5035
panel_toplevel_get_x_centered (PanelToplevel *toplevel)
 
5036
{
 
5037
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
5038
 
 
5039
        return toplevel->priv->x_centered;
 
5040
}
 
5041
 
 
5042
gboolean
 
5043
panel_toplevel_get_y_centered (PanelToplevel *toplevel)
 
5044
{
 
5045
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
5046
 
 
5047
        return toplevel->priv->y_centered;
 
5048
}
 
5049
 
 
5050
/**
 
5051
 * panel_toplevel_set_monitor_internal:
 
5052
 *
 
5053
 * Sets the monitor of the toplevel, but only the internal state. We need to
 
5054
 * make the difference between the internal state and the configuration of the
 
5055
 * user because internal constraints might affect the monitor of the toplevel.
 
5056
 *
 
5057
 * panel_toplevel_set_monitor_internal() won't update the configuration of the
 
5058
 * user.
 
5059
 **/
 
5060
static void
 
5061
panel_toplevel_set_monitor_internal (PanelToplevel *toplevel,
 
5062
                                     int            monitor,
 
5063
                                     gboolean       force_resize)
 
5064
{
 
5065
        if (toplevel->priv->monitor == monitor)
 
5066
                return;
 
5067
 
 
5068
        toplevel->priv->monitor = monitor;
 
5069
 
 
5070
        if (force_resize)
 
5071
                gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
5072
}
 
5073
 
 
5074
/**
 
5075
 * panel_toplevel_update_monitor:
 
5076
 *
 
5077
 * Moves the toplevel to its configured monitor or the first one, if needed.
 
5078
 * This generally happens when the configured monitor was non-existing before,
 
5079
 * and it appeared at runtime, or if it was existing and disappeared.
 
5080
 *
 
5081
 * This must only be called at the beginning of the size request of the
 
5082
 * toplevel because it doesn't queue a size request.
 
5083
 **/
 
5084
static void
 
5085
panel_toplevel_update_monitor (PanelToplevel *toplevel)
 
5086
{
 
5087
        GdkScreen *screen;
 
5088
 
 
5089
        screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
5090
 
 
5091
        /* If we were not using the configured monitor, can we use it now? */
 
5092
        if ((toplevel->priv->configured_monitor != -1) &&
 
5093
            (toplevel->priv->configured_monitor != toplevel->priv->monitor) &&
 
5094
            toplevel->priv->configured_monitor < panel_multiscreen_monitors (screen)) {
 
5095
                panel_toplevel_set_monitor_internal (toplevel,
 
5096
                                                     toplevel->priv->configured_monitor,
 
5097
                                                     FALSE);
 
5098
 
 
5099
        /* else, can we still use the monitor we were using? */
 
5100
        } else if (toplevel->priv->monitor >= panel_multiscreen_monitors (screen)) {
 
5101
                panel_toplevel_set_monitor_internal (toplevel,
 
5102
                                                     0,
 
5103
                                                     FALSE);
 
5104
        }
 
5105
}
 
5106
 
 
5107
void
 
5108
panel_toplevel_set_monitor (PanelToplevel *toplevel,
 
5109
                            int            monitor)
 
5110
{
 
5111
        GdkScreen *screen;
 
5112
 
 
5113
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5114
 
 
5115
        if (toplevel->priv->configured_monitor == monitor)
 
5116
                return;
 
5117
 
 
5118
        toplevel->priv->configured_monitor = monitor;
 
5119
 
 
5120
        /* Only use the configured monitor if it's existing. Else, we ignore
 
5121
         * the non-existing monitor, and keep the old one. The main use case is
 
5122
         * when logging in after having used a multiscreen environment.
 
5123
         * We will put the panel on the monitor 0 for this session, and it will
 
5124
         * move back to the right monitor next time. */
 
5125
        screen = gtk_window_get_screen (GTK_WINDOW (toplevel));
 
5126
        if (monitor < panel_multiscreen_monitors (screen))
 
5127
                panel_toplevel_set_monitor_internal (toplevel, monitor, TRUE);
 
5128
 
 
5129
        panel_toplevel_apply_delayed_settings_queue (toplevel);
 
5130
        g_object_notify (G_OBJECT (toplevel), "monitor");
 
5131
}
 
5132
 
 
5133
int
 
5134
panel_toplevel_get_monitor (PanelToplevel *toplevel)
 
5135
{
 
5136
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), -1);
 
5137
 
 
5138
        return toplevel->priv->monitor;
 
5139
}
 
5140
 
 
5141
void
 
5142
panel_toplevel_set_auto_hide (PanelToplevel *toplevel,
 
5143
                              gboolean       auto_hide)
 
5144
{
 
5145
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5146
 
 
5147
        auto_hide = auto_hide != FALSE;
 
5148
 
 
5149
        if (toplevel->priv->auto_hide == auto_hide)
 
5150
                return;
 
5151
 
 
5152
        toplevel->priv->auto_hide = auto_hide;
 
5153
 
 
5154
        if (toplevel->priv->auto_hide)
 
5155
                panel_toplevel_queue_auto_hide (toplevel);
 
5156
        else
 
5157
                panel_toplevel_queue_auto_unhide (toplevel);
 
5158
 
 
5159
        if (panel_toplevel_update_struts (toplevel, FALSE))
 
5160
                gtk_widget_queue_resize (GTK_WIDGET (toplevel));
 
5161
 
 
5162
        g_object_notify (G_OBJECT (toplevel), "auto-hide");
 
5163
}
 
5164
 
 
5165
gboolean
 
5166
panel_toplevel_get_auto_hide (PanelToplevel *toplevel)
 
5167
{
 
5168
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
5169
 
 
5170
        return toplevel->priv->auto_hide;
 
5171
}
 
5172
 
 
5173
void
 
5174
panel_toplevel_set_hide_delay (PanelToplevel *toplevel,
 
5175
                               int            hide_delay)
 
5176
{
 
5177
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5178
 
 
5179
        if (toplevel->priv->hide_delay == hide_delay)
 
5180
                return;
 
5181
 
 
5182
        toplevel->priv->hide_delay = hide_delay;
 
5183
 
 
5184
        g_object_notify (G_OBJECT (toplevel), "hide-delay");
 
5185
}
 
5186
 
 
5187
int
 
5188
panel_toplevel_get_hide_delay (PanelToplevel *toplevel)
 
5189
{
 
5190
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), -1);
 
5191
 
 
5192
        return toplevel->priv->hide_delay;
 
5193
}
 
5194
 
 
5195
void
 
5196
panel_toplevel_set_unhide_delay (PanelToplevel *toplevel,
 
5197
                                 int            unhide_delay)
 
5198
{
 
5199
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5200
 
 
5201
        if (toplevel->priv->unhide_delay == unhide_delay)
 
5202
                return;
 
5203
 
 
5204
        toplevel->priv->unhide_delay = unhide_delay;
 
5205
 
 
5206
        g_object_notify (G_OBJECT (toplevel), "unhide-delay");
 
5207
}
 
5208
 
 
5209
int
 
5210
panel_toplevel_get_unhide_delay (PanelToplevel *toplevel)
 
5211
{
 
5212
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), -1);
 
5213
 
 
5214
        return toplevel->priv->unhide_delay;
 
5215
}
 
5216
 
 
5217
static void
 
5218
panel_toplevel_set_animate (PanelToplevel *toplevel,
 
5219
                            gboolean       animate)
 
5220
{
 
5221
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5222
 
 
5223
        animate = animate != FALSE;
 
5224
 
 
5225
        if (toplevel->priv->animate == animate)
 
5226
                return;
 
5227
 
 
5228
        toplevel->priv->animate = animate;
 
5229
 
 
5230
        g_object_notify (G_OBJECT (toplevel), "animate");
 
5231
}
 
5232
 
 
5233
gboolean
 
5234
panel_toplevel_get_animate (PanelToplevel *toplevel)
 
5235
{
 
5236
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
5237
 
 
5238
        return toplevel->priv->animate;
 
5239
}
 
5240
 
 
5241
void
 
5242
panel_toplevel_set_animation_speed (PanelToplevel       *toplevel,
 
5243
                                    PanelAnimationSpeed  animation_speed)
 
5244
{
 
5245
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5246
 
 
5247
        if (toplevel->priv->animation_speed == animation_speed)
 
5248
                return;
 
5249
 
 
5250
        toplevel->priv->animation_speed = animation_speed;
 
5251
 
 
5252
        g_object_notify (G_OBJECT (toplevel), "animation-speed");
 
5253
}
 
5254
 
 
5255
PanelAnimationSpeed
 
5256
panel_toplevel_get_animation_speed (PanelToplevel *toplevel)
 
5257
{
 
5258
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), 0);
 
5259
 
 
5260
        return toplevel->priv->animation_speed;
 
5261
}
 
5262
 
 
5263
void
 
5264
panel_toplevel_set_enable_buttons (PanelToplevel *toplevel,
 
5265
                                   gboolean       enable_buttons)
 
5266
{
 
5267
        enable_buttons = enable_buttons != FALSE;
 
5268
 
 
5269
        if (toplevel->priv->buttons_enabled == enable_buttons)
 
5270
                return;
 
5271
 
 
5272
        toplevel->priv->buttons_enabled = enable_buttons;
 
5273
 
 
5274
        panel_toplevel_update_hide_buttons (toplevel);
 
5275
 
 
5276
        g_object_notify (G_OBJECT (toplevel), "buttons-enabled");
 
5277
}
 
5278
 
 
5279
gboolean
 
5280
panel_toplevel_get_enable_buttons (PanelToplevel *toplevel)
 
5281
{
 
5282
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
5283
 
 
5284
        return toplevel->priv->buttons_enabled;
 
5285
}
 
5286
 
 
5287
void
 
5288
panel_toplevel_set_enable_arrows (PanelToplevel *toplevel,
 
5289
                                  gboolean       enable_arrows)
 
5290
{
 
5291
        g_return_if_fail (PANEL_IS_TOPLEVEL (toplevel));
 
5292
 
 
5293
        enable_arrows = enable_arrows != FALSE;
 
5294
 
 
5295
        if (toplevel->priv->arrows_enabled == enable_arrows)
 
5296
                return;
 
5297
 
 
5298
        toplevel->priv->arrows_enabled = enable_arrows;
 
5299
 
 
5300
        panel_toplevel_update_hide_buttons (toplevel);
 
5301
 
 
5302
        g_object_notify (G_OBJECT (toplevel), "arrows-enabled");
 
5303
}
 
5304
 
 
5305
gboolean
 
5306
panel_toplevel_get_enable_arrows (PanelToplevel *toplevel)
 
5307
{
 
5308
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
5309
 
 
5310
        return toplevel->priv->arrows_enabled;
 
5311
}
 
5312
 
 
5313
void
 
5314
panel_toplevel_rotate (PanelToplevel *toplevel,
 
5315
                       gboolean       clockwise)
 
5316
{
 
5317
        PanelOrientation orientation;
 
5318
 
 
5319
        /* Relies on PanelOrientation definition:
 
5320
         *
 
5321
         * typedef enum {
 
5322
         *        PANEL_ORIENTATION_TOP    = 1 << 0,
 
5323
         *        PANEL_ORIENTATION_RIGHT  = 1 << 1,
 
5324
         *        PANEL_ORIENTATION_BOTTOM = 1 << 2,
 
5325
         *        PANEL_ORIENTATION_LEFT   = 1 << 3
 
5326
         * } PanelOrientation;
 
5327
         */
 
5328
 
 
5329
        orientation = toplevel->priv->orientation;
 
5330
 
 
5331
        if (clockwise)
 
5332
                orientation <<= 1;
 
5333
        else
 
5334
                orientation >>= 1;
 
5335
 
 
5336
        if (orientation == 0)
 
5337
                orientation = PANEL_ORIENTATION_LEFT;
 
5338
 
 
5339
        else if (orientation > PANEL_ORIENTATION_LEFT)
 
5340
                orientation = PANEL_ORIENTATION_TOP;
 
5341
 
 
5342
        panel_toplevel_set_orientation (toplevel, orientation);
 
5343
}
 
5344
 
 
5345
PanelState
 
5346
panel_toplevel_get_state (PanelToplevel *toplevel)
 
5347
{
 
5348
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), 0);
 
5349
 
 
5350
        return toplevel->priv->state;
 
5351
}
 
5352
 
 
5353
gboolean
 
5354
panel_toplevel_get_is_hidden (PanelToplevel *toplevel)
 
5355
{
 
5356
        g_return_val_if_fail (PANEL_IS_TOPLEVEL (toplevel), FALSE);
 
5357
 
 
5358
        if (toplevel->priv->state == PANEL_STATE_HIDDEN_UP   ||
 
5359
            toplevel->priv->state == PANEL_STATE_HIDDEN_DOWN ||
 
5360
            toplevel->priv->state == PANEL_STATE_HIDDEN_LEFT ||
 
5361
            toplevel->priv->state == PANEL_STATE_HIDDEN_RIGHT)
 
5362
                return TRUE;
 
5363
 
 
5364
        return FALSE;
 
5365
}
 
5366
 
 
5367
int
 
5368
panel_toplevel_get_minimum_size (PanelToplevel *toplevel)
 
5369
{
 
5370
        return calculate_minimum_height (GTK_WIDGET (toplevel),
 
5371
                                         toplevel->priv->orientation);
 
5372
}
 
5373
 
 
5374
int
 
5375
panel_toplevel_get_maximum_size (PanelToplevel *toplevel)
 
5376
{
 
5377
        int monitor_width, monitor_height;
 
5378
 
 
5379
        panel_toplevel_get_monitor_geometry (toplevel, NULL, NULL,
 
5380
                                             &monitor_width, &monitor_height);
 
5381
 
 
5382
        if (toplevel->priv->orientation & PANEL_HORIZONTAL_MASK)
 
5383
                return monitor_height / MAXIMUM_SIZE_SCREEN_RATIO;
 
5384
        else
 
5385
                return monitor_width / MAXIMUM_SIZE_SCREEN_RATIO;
 
5386
}