gtknotebook.c 260 KB
Newer Older
1
/* -*- Mode: C; c-file-style: "gnu"; tab-width: 8 -*- */
Cody Russell's avatar
Cody Russell committed
2
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
3 4 5
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16 17 18
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
19
 */
20 21

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

28
#include "config.h"
29 30

#include <stdio.h>
31
#include <string.h>
32

33
#include "gtknotebook.h"
34

35 36 37 38
#include "gtkmain.h"
#include "gtkmenu.h"
#include "gtkmenuitem.h"
#include "gtklabel.h"
39
#include "gtkintl.h"
40
#include "gtkmarshalers.h"
41
#include "gtkbindings.h"
42
#include "gtkprivate.h"
43
#include "gtkdnd.h"
44
#include "gtkbuildable.h"
45
#include "gtktypebuiltins.h"
46

47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

/**
 * SECTION:gtknotebook
 * @Short_description: A tabbed notebook container
 * @Title: GtkNotebook
 * @See_also: #GtkContainer
 *
 * The #GtkNotebook widget is a #GtkContainer whose children are pages that
 * can be switched between using tab labels along one edge.
 *
 * There are many configuration options for GtkNotebook. Among other
 * things, you can choose on which edge the tabs appear
 * (see gtk_notebook_set_tab_pos()), whether, if there are too many
 * tabs to fit the notebook should be made bigger or scrolling
 * arrows added (see gtk_notebook_set_scrollable()), and whether there
 * will be a popup menu allowing the users to switch pages.
 * (see gtk_notebook_popup_enable(), gtk_notebook_popup_disable())
 *
 * <refsect2 id="GtkNotebook-BUILDER-UI">
 * <title>GtkNotebook as GtkBuildable</title>
 * <para>
 * The GtkNotebook implementation of the #GtkBuildable interface
 * supports placing children into tabs by specifying "tab" as the
 * "type" attribute of a &lt;child&gt; element. Note that the content
 * of the tab must be created before the tab can be filled.
 * A tab child can be specified without specifying a &lt;child&gt;
 * type attribute.
74
 *
75 76 77
 * To add a child widget in the notebooks action area, specify
 * "action-start" or "action-end" as the "type" attribute of the &lt;child&gt;
 * element.
78
 * </para>
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
 * <example>
 * <title>A UI definition fragment with GtkNotebook</title>
 * <programlisting><![CDATA[
 * <object class="GtkNotebook">
 *   <child>
 *     <object class="GtkLabel" id="notebook-content">
 *       <property name="label">Content</property>
 *     </object>
 *   </child>
 *   <child type="tab">
 *     <object class="GtkLabel" id="notebook-tab">
 *       <property name="label">Tab</property>
 *     </object>
 *   </child>
 * </object>
 * ]]></programlisting>
 * </example>
 * </refsect2>
 */


100
#define SCROLL_DELAY_FACTOR   5
101 102
#define SCROLL_THRESHOLD      12
#define DND_THRESHOLD_MULTIPLIER 4
103 104
#define FRAMES_PER_SECOND     45
#define MSECS_BETWEEN_UPDATES (1000 / FRAMES_PER_SECOND)
Elliot Lee's avatar
Elliot Lee committed
105

106
typedef struct _GtkNotebookPage GtkNotebookPage;
107 108 109 110 111 112 113 114 115 116 117 118 119 120

typedef enum
{
  DRAG_OPERATION_NONE,
  DRAG_OPERATION_REORDER,
  DRAG_OPERATION_DETACH
} GtkNotebookDragOperation;

enum {
  ACTION_WIDGET_START,
  ACTION_WIDGET_END,
  N_ACTION_WIDGETS
};

121
struct _GtkNotebookPrivate
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
{
  GtkNotebookDragOperation   operation;
  GtkNotebookPage           *cur_page;
  GtkNotebookPage           *detached_tab;
  GtkTargetList             *source_targets;
  GtkWidget                 *action_widget[N_ACTION_WIDGETS];
  GtkWidget                 *dnd_window;
  GtkWidget                 *menu;

  GdkWindow               *drag_window;
  GdkWindow               *event_window;

  GList         *children;
  GList         *first_tab;             /* The first tab visible (for scrolling notebooks) */
  GList         *focus_tab;

  gint           drag_begin_x;
  gint           drag_begin_y;
  gint           drag_offset_x;
  gint           drag_offset_y;
  gint           drag_window_x;
  gint           drag_window_y;
  gint           mouse_x;
  gint           mouse_y;
  gint           pressed_button;

148
  GQuark         group;
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

  guint          dnd_timer;
  guint          switch_tab_timer;

  guint16        tab_hborder;
  guint16        tab_vborder;

  guint32        timer;
  guint32        timestamp;

  guint          button             : 2;
  guint          child_has_focus    : 1;
  guint          click_child        : 3;
  guint          during_detach      : 1;
  guint          during_reorder     : 1;
  guint          focus_out          : 1; /* Flag used by ::move-focus-out implementation */
  guint          has_scrolled       : 1;
  guint          have_visible_child : 1;
  guint          homogeneous        : 1;
  guint          in_child           : 3;
  guint          need_timer         : 1;
  guint          show_border        : 1;
  guint          show_tabs          : 1;
  guint          scrollable         : 1;
  guint          tab_pos            : 2;

  guint          has_before_previous : 1;
  guint          has_before_next     : 1;
  guint          has_after_previous  : 1;
  guint          has_after_next      : 1;
};

181 182
enum {
  SWITCH_PAGE,
183 184
  FOCUS_TAB,
  SELECT_PAGE,
185
  CHANGE_CURRENT_PAGE,
186
  MOVE_FOCUS_OUT,
187
  REORDER_TAB,
188 189 190
  PAGE_REORDERED,
  PAGE_REMOVED,
  PAGE_ADDED,
191
  CREATE_WINDOW,
192 193 194
  LAST_SIGNAL
};

195 196 197 198 199
enum {
  STEP_PREV,
  STEP_NEXT
};

200 201 202 203 204 205 206 207 208
typedef enum
{
  ARROW_NONE,
  ARROW_LEFT_BEFORE,
  ARROW_RIGHT_BEFORE,
  ARROW_LEFT_AFTER,
  ARROW_RIGHT_AFTER
} GtkNotebookArrow;

209 210 211 212 213 214 215
typedef enum
{
  POINTER_BEFORE,
  POINTER_AFTER,
  POINTER_BETWEEN
} GtkNotebookPointerPosition;

216 217 218
#define ARROW_IS_LEFT(arrow)  ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_LEFT_AFTER)
#define ARROW_IS_BEFORE(arrow) ((arrow) == ARROW_LEFT_BEFORE || (arrow) == ARROW_RIGHT_BEFORE)

219
enum {
220 221 222 223 224 225 226
  PROP_0,
  PROP_TAB_POS,
  PROP_SHOW_TABS,
  PROP_SHOW_BORDER,
  PROP_SCROLLABLE,
  PROP_PAGE,
  PROP_ENABLE_POPUP,
227
  PROP_GROUP_NAME
228 229 230
};

enum {
Tim Janik's avatar
Tim Janik committed
231 232 233 234 235 236
  CHILD_PROP_0,
  CHILD_PROP_TAB_LABEL,
  CHILD_PROP_MENU_LABEL,
  CHILD_PROP_POSITION,
  CHILD_PROP_TAB_EXPAND,
  CHILD_PROP_TAB_FILL,
237 238
  CHILD_PROP_REORDERABLE,
  CHILD_PROP_DETACHABLE
239 240
};

241 242
#define GTK_NOTEBOOK_PAGE(_glist_)         ((GtkNotebookPage *)((GList *)(_glist_))->data)

243 244 245 246 247 248 249
/* some useful defines for calculating coords */
#define PAGE_LEFT_X(_page_)   (((GtkNotebookPage *) (_page_))->allocation.x)
#define PAGE_RIGHT_X(_page_)  (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width)
#define PAGE_MIDDLE_X(_page_) (((GtkNotebookPage *) (_page_))->allocation.x + ((GtkNotebookPage *) (_page_))->allocation.width / 2)
#define PAGE_TOP_Y(_page_)    (((GtkNotebookPage *) (_page_))->allocation.y)
#define PAGE_BOTTOM_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height)
#define PAGE_MIDDLE_Y(_page_) (((GtkNotebookPage *) (_page_))->allocation.y + ((GtkNotebookPage *) (_page_))->allocation.height / 2)
250
#define NOTEBOOK_IS_TAB_LABEL_PARENT(_notebook_,_page_) (gtk_widget_get_parent (((GtkNotebookPage *) (_page_))->tab_label) == ((GtkWidget *) (_notebook_)))
251

252 253 254 255 256
struct _GtkNotebookPage
{
  GtkWidget *child;
  GtkWidget *tab_label;
  GtkWidget *menu_label;
257
  GtkWidget *last_focus_child;  /* Last descendant of the page that had focus */
258

259 260
  guint default_menu : 1;       /* If true, we create the menu label ourself */
  guint default_tab  : 1;       /* If true, we create the tab label ourself */
261 262
  guint expand       : 1;
  guint fill         : 1;
263 264
  guint reorderable  : 1;
  guint detachable   : 1;
265

266 267 268 269 270
  /* if true, the tab label was visible on last allocation; we track this so
   * that we know to redraw the tab area if a tab label was hidden then shown
   * without changing position */
  guint tab_allocated_visible : 1;

271 272
  GtkRequisition requisition;
  GtkAllocation allocation;
273

274 275
  gulong mnemonic_activate_signal;
  gulong notify_visible_handler;
276 277
};

278
static const GtkTargetEntry notebook_targets [] = {
279
  { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, 0 },
280 281
};

282 283
#ifdef G_DISABLE_CHECKS
#define CHECK_FIND_CHILD(notebook, child)                           \
284
 gtk_notebook_find_child (notebook, child, G_STRLOC)
285 286
#else
#define CHECK_FIND_CHILD(notebook, child)                           \
287
 gtk_notebook_find_child (notebook, child, NULL)
288
#endif
289

290
/*** GtkNotebook Methods ***/
291
static gboolean gtk_notebook_select_page         (GtkNotebook      *notebook,
292
                                                  gboolean          move_focus);
293
static gboolean gtk_notebook_focus_tab           (GtkNotebook      *notebook,
294
                                                  GtkNotebookTab    type);
295
static gboolean gtk_notebook_change_current_page (GtkNotebook      *notebook,
296
                                                  gint              offset);
297
static void     gtk_notebook_move_focus_out      (GtkNotebook      *notebook,
298
                                                  GtkDirectionType  direction_type);
299
static gboolean gtk_notebook_reorder_tab         (GtkNotebook      *notebook,
300 301
                                                  GtkDirectionType  direction_type,
                                                  gboolean          move_to_last);
302
static void     gtk_notebook_remove_tab_label    (GtkNotebook      *notebook,
303
                                                  GtkNotebookPage  *page);
304 305 306
static void     gtk_notebook_set_tab_label_packing   (GtkNotebook  *notebook,
                                                      GtkWidget    *child,
                                                      gboolean      expand,
307
                                                      gboolean      fill);
308 309 310
static void     gtk_notebook_query_tab_label_packing (GtkNotebook  *notebook,
                                                      GtkWidget    *child,
                                                      gboolean     *expand,
311
                                                      gboolean     *fill);
312

313
/*** GObject Methods ***/
314 315 316 317 318 319 320 321
static void gtk_notebook_set_property        (GObject         *object,
                                              guint            prop_id,
                                              const GValue    *value,
                                              GParamSpec      *pspec);
static void gtk_notebook_get_property        (GObject         *object,
                                              guint            prop_id,
                                              GValue          *value,
                                              GParamSpec      *pspec);
322

323
/*** GtkWidget Methods ***/
324
static void gtk_notebook_destroy             (GtkWidget        *widget);
325 326 327
static void gtk_notebook_map                 (GtkWidget        *widget);
static void gtk_notebook_unmap               (GtkWidget        *widget);
static void gtk_notebook_realize             (GtkWidget        *widget);
328
static void gtk_notebook_unrealize           (GtkWidget        *widget);
329
static void gtk_notebook_get_preferred_width (GtkWidget        *widget,
330 331
                                              gint             *minimum,
                                              gint             *natural);
332
static void gtk_notebook_get_preferred_height(GtkWidget        *widget,
333 334
                                              gint             *minimum,
                                              gint             *natural);
335 336 337 338 339 340 341 342 343 344
static void gtk_notebook_get_preferred_width_for_height
                                             (GtkWidget        *widget,
                                              gint              height,
                                              gint             *minimum,
                                              gint             *natural);
static void gtk_notebook_get_preferred_height_for_width
                                             (GtkWidget        *widget,
                                              gint              width,
                                              gint             *minimum,
                                              gint             *natural);
345
static void gtk_notebook_size_allocate       (GtkWidget        *widget,
346
                                              GtkAllocation    *allocation);
347 348
static gint gtk_notebook_draw                (GtkWidget        *widget,
                                              cairo_t          *cr);
349
static gint gtk_notebook_button_press        (GtkWidget        *widget,
350
                                              GdkEventButton   *event);
351
static gint gtk_notebook_button_release      (GtkWidget        *widget,
352
                                              GdkEventButton   *event);
353
static gboolean gtk_notebook_popup_menu      (GtkWidget        *widget);
354
static gint gtk_notebook_leave_notify        (GtkWidget        *widget,
355
                                              GdkEventCrossing *event);
356
static gint gtk_notebook_motion_notify       (GtkWidget        *widget,
357
                                              GdkEventMotion   *event);
358
static gint gtk_notebook_focus_in            (GtkWidget        *widget,
359
                                              GdkEventFocus    *event);
360
static gint gtk_notebook_focus_out           (GtkWidget        *widget,
361
                                              GdkEventFocus    *event);
Matthias Clasen's avatar
Matthias Clasen committed
362
static void gtk_notebook_grab_notify         (GtkWidget          *widget,
363
                                              gboolean            was_grabbed);
364
static void gtk_notebook_state_flags_changed (GtkWidget          *widget,
365
                                              GtkStateFlags       previous_state);
366
static gint gtk_notebook_focus               (GtkWidget        *widget,
367
                                              GtkDirectionType  direction);
368
static void gtk_notebook_style_updated       (GtkWidget        *widget);
369

370 371
/*** Drag and drop Methods ***/
static void gtk_notebook_drag_begin          (GtkWidget        *widget,
372
                                              GdkDragContext   *context);
373
static void gtk_notebook_drag_end            (GtkWidget        *widget,
374
                                              GdkDragContext   *context);
375
static gboolean gtk_notebook_drag_failed     (GtkWidget        *widget,
376 377
                                              GdkDragContext   *context,
                                              GtkDragResult     result);
378
static gboolean gtk_notebook_drag_motion     (GtkWidget        *widget,
379 380 381 382
                                              GdkDragContext   *context,
                                              gint              x,
                                              gint              y,
                                              guint             time);
383
static void gtk_notebook_drag_leave          (GtkWidget        *widget,
384 385
                                              GdkDragContext   *context,
                                              guint             time);
386
static gboolean gtk_notebook_drag_drop       (GtkWidget        *widget,
387 388 389 390
                                              GdkDragContext   *context,
                                              gint              x,
                                              gint              y,
                                              guint             time);
391
static void gtk_notebook_drag_data_get       (GtkWidget        *widget,
392 393 394 395
                                              GdkDragContext   *context,
                                              GtkSelectionData *data,
                                              guint             info,
                                              guint             time);
396
static void gtk_notebook_drag_data_received  (GtkWidget        *widget,
397 398 399 400 401 402
                                              GdkDragContext   *context,
                                              gint              x,
                                              gint              y,
                                              GtkSelectionData *data,
                                              guint             info,
                                              guint             time);
403

404
/*** GtkContainer Methods ***/
Tim Janik's avatar
Tim Janik committed
405
static void gtk_notebook_set_child_property  (GtkContainer     *container,
406 407 408 409
                                              GtkWidget        *child,
                                              guint             property_id,
                                              const GValue     *value,
                                              GParamSpec       *pspec);
Tim Janik's avatar
Tim Janik committed
410
static void gtk_notebook_get_child_property  (GtkContainer     *container,
411 412 413 414
                                              GtkWidget        *child,
                                              guint             property_id,
                                              GValue           *value,
                                              GParamSpec       *pspec);
415
static void gtk_notebook_add                 (GtkContainer     *container,
416
                                              GtkWidget        *widget);
417
static void gtk_notebook_remove              (GtkContainer     *container,
418
                                              GtkWidget        *widget);
419
static void gtk_notebook_set_focus_child     (GtkContainer     *container,
420
                                              GtkWidget        *child);
Manish Singh's avatar
Manish Singh committed
421
static GType gtk_notebook_child_type       (GtkContainer     *container);
422
static void gtk_notebook_forall              (GtkContainer     *container,
423 424 425
                                              gboolean          include_internals,
                                              GtkCallback       callback,
                                              gpointer          callback_data);
426 427
static GtkWidgetPath * gtk_notebook_get_path_for_child (GtkContainer *container,
                                                        GtkWidget    *widget);
428

429 430
/*** GtkNotebook Methods ***/
static gint gtk_notebook_real_insert_page    (GtkNotebook      *notebook,
431 432 433 434
                                              GtkWidget        *child,
                                              GtkWidget        *tab_label,
                                              GtkWidget        *menu_label,
                                              gint              position);
435

436 437 438 439 440
static GtkNotebook *gtk_notebook_create_window (GtkNotebook    *notebook,
                                                GtkWidget      *page,
                                                gint            x,
                                                gint            y);

441
/*** GtkNotebook Private Functions ***/
442 443
static void gtk_notebook_redraw_tabs         (GtkNotebook      *notebook);
static void gtk_notebook_redraw_arrows       (GtkNotebook      *notebook);
444
static void gtk_notebook_real_remove         (GtkNotebook      *notebook,
445
                                              GList            *list);
446 447
static void gtk_notebook_update_labels       (GtkNotebook      *notebook);
static gint gtk_notebook_timer               (GtkNotebook      *notebook);
448
static void gtk_notebook_set_scroll_timer    (GtkNotebook *notebook);
449
static gint gtk_notebook_page_compare        (gconstpointer     a,
450
                                              gconstpointer     b);
451
static GList* gtk_notebook_find_child        (GtkNotebook      *notebook,
452 453
                                              GtkWidget        *child,
                                              const gchar      *function);
454
static GList * gtk_notebook_search_page      (GtkNotebook      *notebook,
455 456 457
                                              GList            *list,
                                              gint              direction,
                                              gboolean          find_visible);
458
static void  gtk_notebook_child_reordered    (GtkNotebook      *notebook,
459
                                              GtkNotebookPage  *page);
460

461
/*** GtkNotebook Drawing Functions ***/
462
static void gtk_notebook_paint               (GtkWidget        *widget,
463
                                              cairo_t          *cr);
464
static void gtk_notebook_draw_tab            (GtkNotebook      *notebook,
465 466
                                              GtkNotebookPage  *page,
                                              cairo_t          *cr,
467
                                              GtkRegionFlags    flags);
468
static void gtk_notebook_draw_arrow          (GtkNotebook      *notebook,
469
                                              cairo_t          *cr,
470
                                              GtkNotebookArrow  arrow);
471

472
/*** GtkNotebook Size Allocate Functions ***/
473
static void gtk_notebook_pages_allocate      (GtkNotebook      *notebook);
474
static gboolean gtk_notebook_page_allocate   (GtkNotebook      *notebook,
475
                                              GtkNotebookPage  *page);
476
static void gtk_notebook_calc_tabs           (GtkNotebook      *notebook,
477 478 479 480
                                              GList            *start,
                                              GList           **end,
                                              gint             *tab_space,
                                              guint             direction);
481

482
/*** GtkNotebook Page Switch Methods ***/
483
static void gtk_notebook_real_switch_page    (GtkNotebook      *notebook,
484 485
                                              GtkWidget        *child,
                                              guint             page_num);
486

487
/*** GtkNotebook Page Switch Functions ***/
488
static void gtk_notebook_switch_page         (GtkNotebook      *notebook,
489
                                              GtkNotebookPage  *page);
490
static gint gtk_notebook_page_select         (GtkNotebook      *notebook,
491
                                              gboolean          move_focus);
492 493
static void gtk_notebook_switch_focus_tab    (GtkNotebook      *notebook,
                                              GList            *new_child);
494
static void gtk_notebook_menu_switch_page    (GtkWidget        *widget,
495
                                              GtkNotebookPage  *page);
496

497
/*** GtkNotebook Menu Functions ***/
498
static void gtk_notebook_menu_item_create    (GtkNotebook      *notebook,
499
                                              GList            *list);
500
static void gtk_notebook_menu_label_unparent (GtkWidget        *widget,
501
                                              gpointer          data);
502
static void gtk_notebook_menu_detacher       (GtkWidget        *widget,
503
                                              GtkMenu          *menu);
504

505
/*** GtkNotebook Private Setters ***/
506 507
static void gtk_notebook_update_tab_states             (GtkNotebook *notebook);
static gboolean gtk_notebook_mnemonic_activate_switch_page (GtkWidget *child,
508 509
                                                            gboolean overload,
                                                            gpointer data);
510

511 512
static gboolean focus_tabs_in  (GtkNotebook      *notebook);
static gboolean focus_child_in (GtkNotebook      *notebook,
513
                                GtkDirectionType  direction);
Elliot Lee's avatar
Elliot Lee committed
514

515
static void stop_scrolling (GtkNotebook *notebook);
516
static void do_detach_tab  (GtkNotebook *from,
517 518 519 520
                            GtkNotebook *to,
                            GtkWidget   *child,
                            gint         x,
                            gint         y);
521

522 523
/* GtkBuildable */
static void gtk_notebook_buildable_init           (GtkBuildableIface *iface);
524
static void gtk_notebook_buildable_add_child      (GtkBuildable *buildable,
525 526 527
                                                   GtkBuilder   *builder,
                                                   GObject      *child,
                                                   const gchar  *type);
528

529
static guint notebook_signals[LAST_SIGNAL] = { 0 };
Elliot Lee's avatar
Elliot Lee committed
530

531
G_DEFINE_TYPE_WITH_CODE (GtkNotebook, gtk_notebook, GTK_TYPE_CONTAINER,
532 533
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                gtk_notebook_buildable_init))
Elliot Lee's avatar
Elliot Lee committed
534

535 536
static void
add_tab_bindings (GtkBindingSet    *binding_set,
537 538
                  GdkModifierType   modifiers,
                  GtkDirectionType  direction)
539
{
540
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
541 542
                                "move_focus_out", 1,
                                GTK_TYPE_DIRECTION_TYPE, direction);
543
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
544 545 546 547 548 549
                                "move_focus_out", 1,
                                GTK_TYPE_DIRECTION_TYPE, direction);
}

static void
add_arrow_bindings (GtkBindingSet    *binding_set,
550 551
                    guint             keysym,
                    GtkDirectionType  direction)
552
{
553
  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
554

555 556 557 558 559 560 561 562
  gtk_binding_entry_add_signal (binding_set, keysym, GDK_CONTROL_MASK,
                                "move_focus_out", 1,
                                GTK_TYPE_DIRECTION_TYPE, direction);
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_CONTROL_MASK,
                                "move_focus_out", 1,
                                GTK_TYPE_DIRECTION_TYPE, direction);
}

563 564
static void
add_reorder_bindings (GtkBindingSet    *binding_set,
565 566 567
                      guint             keysym,
                      GtkDirectionType  direction,
                      gboolean          move_to_last)
568
{
569
  guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left;
570 571

  gtk_binding_entry_add_signal (binding_set, keysym, GDK_MOD1_MASK,
572 573 574
                                "reorder_tab", 2,
                                GTK_TYPE_DIRECTION_TYPE, direction,
                                G_TYPE_BOOLEAN, move_to_last);
575
  gtk_binding_entry_add_signal (binding_set, keypad_keysym, GDK_MOD1_MASK,
576 577 578
                                "reorder_tab", 2,
                                GTK_TYPE_DIRECTION_TYPE, direction,
                                G_TYPE_BOOLEAN, move_to_last);
579 580
}

581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
static gboolean
gtk_object_handled_accumulator (GSignalInvocationHint *ihint,
                                GValue                *return_accu,
                                const GValue          *handler_return,
                                gpointer               dummy)
{
  gboolean continue_emission;
  GObject *object;

  object = g_value_get_object (handler_return);
  g_value_set_object (return_accu, object);
  continue_emission = !object;

  return continue_emission;
}

597
static void
598 599 600
gtk_notebook_compute_expand (GtkWidget *widget,
                             gboolean  *hexpand_p,
                             gboolean  *vexpand_p)
601
{
602
  GtkNotebook *notebook = GTK_NOTEBOOK (widget);
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
  GtkNotebookPrivate *priv = notebook->priv;
  gboolean hexpand;
  gboolean vexpand;
  GList *list;
  GtkNotebookPage *page;

  hexpand = FALSE;
  vexpand = FALSE;

  for (list = priv->children; list; list = list->next)
    {
      page = list->data;

      hexpand = hexpand ||
        gtk_widget_compute_expand (page->child, GTK_ORIENTATION_HORIZONTAL);

      vexpand = vexpand ||
        gtk_widget_compute_expand (page->child, GTK_ORIENTATION_VERTICAL);

      if (hexpand & vexpand)
        break;
    }

  *hexpand_p = hexpand;
  *vexpand_p = vexpand;
}

Elliot Lee's avatar
Elliot Lee committed
630 631 632
static void
gtk_notebook_class_init (GtkNotebookClass *class)
{
Tim Janik's avatar
Tim Janik committed
633 634 635
  GObjectClass   *gobject_class = G_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
636
  GtkBindingSet *binding_set;
637

638 639
  gobject_class->set_property = gtk_notebook_set_property;
  gobject_class->get_property = gtk_notebook_get_property;
640

641
  widget_class->destroy = gtk_notebook_destroy;
Elliot Lee's avatar
Elliot Lee committed
642 643 644
  widget_class->map = gtk_notebook_map;
  widget_class->unmap = gtk_notebook_unmap;
  widget_class->realize = gtk_notebook_realize;
645
  widget_class->unrealize = gtk_notebook_unrealize;
646 647
  widget_class->get_preferred_width = gtk_notebook_get_preferred_width;
  widget_class->get_preferred_height = gtk_notebook_get_preferred_height;
648 649
  widget_class->get_preferred_width_for_height = gtk_notebook_get_preferred_width_for_height;
  widget_class->get_preferred_height_for_width = gtk_notebook_get_preferred_height_for_width;
Elliot Lee's avatar
Elliot Lee committed
650
  widget_class->size_allocate = gtk_notebook_size_allocate;
651
  widget_class->draw = gtk_notebook_draw;
Elliot Lee's avatar
Elliot Lee committed
652
  widget_class->button_press_event = gtk_notebook_button_press;
653
  widget_class->button_release_event = gtk_notebook_button_release;
654
  widget_class->popup_menu = gtk_notebook_popup_menu;
655 656
  widget_class->leave_notify_event = gtk_notebook_leave_notify;
  widget_class->motion_notify_event = gtk_notebook_motion_notify;
Matthias Clasen's avatar
Matthias Clasen committed
657
  widget_class->grab_notify = gtk_notebook_grab_notify;
658
  widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
659
  widget_class->focus_in_event = gtk_notebook_focus_in;
660
  widget_class->focus_out_event = gtk_notebook_focus_out;
661
  widget_class->focus = gtk_notebook_focus;
662
  widget_class->style_updated = gtk_notebook_style_updated;
663
  widget_class->drag_begin = gtk_notebook_drag_begin;
664
  widget_class->drag_end = gtk_notebook_drag_end;
665
  widget_class->drag_motion = gtk_notebook_drag_motion;
666
  widget_class->drag_leave = gtk_notebook_drag_leave;
667 668 669
  widget_class->drag_drop = gtk_notebook_drag_drop;
  widget_class->drag_data_get = gtk_notebook_drag_data_get;
  widget_class->drag_data_received = gtk_notebook_drag_data_received;
670
  widget_class->drag_failed = gtk_notebook_drag_failed;
671
  widget_class->compute_expand = gtk_notebook_compute_expand;
672

Elliot Lee's avatar
Elliot Lee committed
673 674
  container_class->add = gtk_notebook_add;
  container_class->remove = gtk_notebook_remove;
675
  container_class->forall = gtk_notebook_forall;
676
  container_class->set_focus_child = gtk_notebook_set_focus_child;
Tim Janik's avatar
Tim Janik committed
677 678
  container_class->get_child_property = gtk_notebook_get_child_property;
  container_class->set_child_property = gtk_notebook_set_child_property;
679
  container_class->child_type = gtk_notebook_child_type;
680
  container_class->get_path_for_child = gtk_notebook_get_path_for_child;
681

682
  class->switch_page = gtk_notebook_real_switch_page;
683
  class->insert_page = gtk_notebook_real_insert_page;
684

685 686
  class->focus_tab = gtk_notebook_focus_tab;
  class->select_page = gtk_notebook_select_page;
687
  class->change_current_page = gtk_notebook_change_current_page;
688
  class->move_focus_out = gtk_notebook_move_focus_out;
689
  class->reorder_tab = gtk_notebook_reorder_tab;
690
  class->create_window = gtk_notebook_create_window;
691

692
  g_object_class_install_property (gobject_class,
693 694 695 696 697 698 699 700
                                   PROP_PAGE,
                                   g_param_spec_int ("page",
                                                     P_("Page"),
                                                     P_("The index of the current page"),
                                                     -1,
                                                     G_MAXINT,
                                                     -1,
                                                     GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
701
  g_object_class_install_property (gobject_class,
702 703 704 705 706 707 708
                                   PROP_TAB_POS,
                                   g_param_spec_enum ("tab-pos",
                                                      P_("Tab Position"),
                                                      P_("Which side of the notebook holds the tabs"),
                                                      GTK_TYPE_POSITION_TYPE,
                                                      GTK_POS_TOP,
                                                      GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
709
  g_object_class_install_property (gobject_class,
710 711 712 713 714 715
                                   PROP_SHOW_TABS,
                                   g_param_spec_boolean ("show-tabs",
                                                         P_("Show Tabs"),
                                                         P_("Whether tabs should be shown"),
                                                         TRUE,
                                                         GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
716
  g_object_class_install_property (gobject_class,
717 718 719 720 721 722
                                   PROP_SHOW_BORDER,
                                   g_param_spec_boolean ("show-border",
                                                         P_("Show Border"),
                                                         P_("Whether the border should be shown"),
                                                         TRUE,
                                                         GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
723
  g_object_class_install_property (gobject_class,
724 725 726 727 728 729
                                   PROP_SCROLLABLE,
                                   g_param_spec_boolean ("scrollable",
                                                         P_("Scrollable"),
                                                         P_("If TRUE, scroll arrows are added if there are too many tabs to fit"),
                                                         FALSE,
                                                         GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
730
  g_object_class_install_property (gobject_class,
731 732 733 734 735 736
                                   PROP_ENABLE_POPUP,
                                   g_param_spec_boolean ("enable-popup",
                                                         P_("Enable Popup"),
                                                         P_("If TRUE, pressing the right mouse button on the notebook pops up a menu that you can use to go to a page"),
                                                         FALSE,
                                                         GTK_PARAM_READWRITE));
Matthias Clasen's avatar
Matthias Clasen committed
737 738

  /**
739
   * GtkNotebook:group-name:
Matthias Clasen's avatar
Matthias Clasen committed
740
   *
741
   * Group name for tab drag and drop.
Matthias Clasen's avatar
Matthias Clasen committed
742 743
   *
   * Since: 2.24
744
   */
745
  g_object_class_install_property (gobject_class,
746 747 748 749
                                   PROP_GROUP_NAME,
                                   g_param_spec_string ("group-name",
                                                        P_("Group Name"),
                                                        P_("Group name for tab drag and drop"),
750
                                                        NULL,
751
                                                        GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
752 753

  gtk_container_class_install_child_property (container_class,
754 755 756 757 758 759
                                              CHILD_PROP_TAB_LABEL,
                                              g_param_spec_string ("tab-label",
                                                                   P_("Tab label"),
                                                                   P_("The string displayed on the child's tab label"),
                                                                   NULL,
                                                                   GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
760
  gtk_container_class_install_child_property (container_class,
761 762 763 764 765 766
                                              CHILD_PROP_MENU_LABEL,
                                              g_param_spec_string ("menu-label",
                                                                   P_("Menu label"),
                                                                   P_("The string displayed in the child's menu entry"),
                                                                   NULL,
                                                                   GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
767
  gtk_container_class_install_child_property (container_class,
768 769 770 771 772 773
                                              CHILD_PROP_POSITION,
                                              g_param_spec_int ("position",
                                                                P_("Position"),
                                                                P_("The index of the child in the parent"),
                                                                -1, G_MAXINT, 0,
                                                                GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
774
  gtk_container_class_install_child_property (container_class,
775 776 777 778 779 780
                                              CHILD_PROP_TAB_EXPAND,
                                              g_param_spec_boolean ("tab-expand",
                                                                    P_("Tab expand"),
                                                                    P_("Whether to expand the child's tab"),
                                                                    FALSE,
                                                                    GTK_PARAM_READWRITE));
Tim Janik's avatar
Tim Janik committed
781
  gtk_container_class_install_child_property (container_class,
782 783 784 785 786 787
                                              CHILD_PROP_TAB_FILL,
                                              g_param_spec_boolean ("tab-fill",
                                                                    P_("Tab fill"),
                                                                    P_("Whether the child's tab should fill the allocated area"),
                                                                    TRUE,
                                                                    GTK_PARAM_READWRITE));
788

789
  gtk_container_class_install_child_property (container_class,
790 791 792 793 794 795
                                              CHILD_PROP_REORDERABLE,
                                              g_param_spec_boolean ("reorderable",
                                                                    P_("Tab reorderable"),
                                                                    P_("Whether the tab is reorderable by user action"),
                                                                    FALSE,
                                                                    GTK_PARAM_READWRITE));
796
  gtk_container_class_install_child_property (container_class,
797 798 799 800 801 802
                                              CHILD_PROP_DETACHABLE,
                                              g_param_spec_boolean ("detachable",
                                                                    P_("Tab detachable"),
                                                                    P_("Whether the tab is detachable"),
                                                                    FALSE,
                                                                    GTK_PARAM_READWRITE));
803 804 805 806

/**
 * GtkNotebook:has-secondary-backward-stepper:
 *
807 808
 * The "has-secondary-backward-stepper" property determines whether
 * a second backward arrow button is displayed on the opposite end
809 810 811
 * of the tab area.
 *
 * Since: 2.4
812
 */
813
  gtk_widget_class_install_style_property (widget_class,
814 815 816 817 818
                                           g_param_spec_boolean ("has-secondary-backward-stepper",
                                                                 P_("Secondary backward stepper"),
                                                                 P_("Display a second backward arrow button on the opposite end of the tab area"),
                                                                 FALSE,
                                                                 GTK_PARAM_READABLE));
819

820 821 822
/**
 * GtkNotebook:has-secondary-forward-stepper:
 *
823 824
 * The "has-secondary-forward-stepper" property determines whether
 * a second forward arrow button is displayed on the opposite end
825 826 827
 * of the tab area.
 *
 * Since: 2.4
828
 */
829
  gtk_widget_class_install_style_property (widget_class,
830 831 832 833 834
                                           g_param_spec_boolean ("has-secondary-forward-stepper",
                                                                 P_("Secondary forward stepper"),
                                                                 P_("Display a second forward arrow button on the opposite end of the tab area"),
                                                                 FALSE,
                                                                 GTK_PARAM_READABLE));
835

836 837 838
/**
 * GtkNotebook:has-backward-stepper:
 *
839
 * The "has-backward-stepper" property determines whether
840 841 842
 * the standard backward arrow button is displayed.
 *
 * Since: 2.4
843
 */
844
  gtk_widget_class_install_style_property (widget_class,
845 846 847 848 849
                                           g_param_spec_boolean ("has-backward-stepper",
                                                                 P_("Backward stepper"),
                                                                 P_("Display the standard backward arrow button"),
                                                                 TRUE,
                                                                 GTK_PARAM_READABLE));
850

851 852 853
/**
 * GtkNotebook:has-forward-stepper:
 *
854
 * The "has-forward-stepper" property determines whether
855 856 857
 * the standard forward arrow button is displayed.
 *
 * Since: 2.4
858
 */
859
  gtk_widget_class_install_style_property (widget_class,
860 861 862 863 864 865
                                           g_param_spec_boolean ("has-forward-stepper",
                                                                 P_("Forward stepper"),
                                                                 P_("Display the standard forward arrow button"),
                                                                 TRUE,
                                                                 GTK_PARAM_READABLE));

866 867 868 869 870 871 872
/**
 * GtkNotebook:tab-overlap:
 *
 * The "tab-overlap" property defines size of tab overlap
 * area.
 *
 * Since: 2.10
873
 */
874
  gtk_widget_class_install_style_property (widget_class,
875 876 877 878 879 880 881
                                           g_param_spec_int ("tab-overlap",
                                                             P_("Tab overlap"),
                                                             P_("Size of tab overlap area"),
                                                             G_MININT,
                                                             G_MAXINT,
                                                             2,
                                                             GTK_PARAM_READABLE));
882 883 884 885 886 887 888

/**
 * GtkNotebook:tab-curvature:
 *
 * The "tab-curvature" property defines size of tab curvature.
 *
 * Since: 2.10
889
 */
890
  gtk_widget_class_install_style_property (widget_class,
891 892 893 894 895 896 897
                                           g_param_spec_int ("tab-curvature",
                                                             P_("Tab curvature"),
                                                             P_("Size of tab curvature"),
                                                             0,
                                                             G_MAXINT,
                                                             1,
                                                             GTK_PARAM_READABLE));
898

899 900 901
  /**
   * GtkNotebook:arrow-spacing:
   *
902
   * The "arrow-spacing" property defines the spacing between the scroll
903 904 905 906 907 908
   * arrows and the tabs.
   *
   * Since: 2.10
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("arrow-spacing",
909 910
                                                             P_("Arrow spacing"),
                                                             P_("Scroll arrow spacing"),
911 912 913 914 915
                                                             0,
                                                             G_MAXINT,
                                                             0,
                                                             GTK_PARAM_READABLE));

916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
  /**
   * GtkNotebook:initial-gap:
   *
   * The "initial-gap" property defines the minimum size for the initial
   * gap between the first tab.
   *
   * Since: 3.2
   */
  gtk_widget_class_install_style_property (widget_class,
                                           g_param_spec_int ("initial-gap",
                                                             P_("Initial gap"),
                                                             P_("Initial gap before the first tab"),
                                                             0,
                                                             G_MAXINT,
                                                             0,
                                                             GTK_PARAM_READABLE));

933 934 935 936 937 938 939 940
  /**
   * GtkNotebook::switch-page:
   * @notebook: the object which received the signal.
   * @page: the new current page
   * @page_num: the index of the page
   *
   * Emitted when the user or a function changes the current page.
   */
941
  notebook_signals[SWITCH_PAGE] =
942
    g_signal_new (I_("switch-page"),
943 944 945 946 947 948 949 950 951
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkNotebookClass, switch_page),
                  NULL, NULL,
                  _gtk_marshal_VOID__OBJECT_UINT,
                  G_TYPE_NONE, 2,
                  GTK_TYPE_WIDGET,
                  G_TYPE_UINT);
  notebook_signals[FOCUS_TAB] =
952
    g_signal_new (I_("focus-tab"),
Manish Singh's avatar
Manish Singh committed
953
                  G_TYPE_FROM_CLASS (gobject_class),
954 955 956
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkNotebookClass, focus_tab),
                  NULL, NULL,
957
                  _gtk_marshal_BOOLEAN__ENUM,
958
                  G_TYPE_BOOLEAN, 1,
959
                  GTK_TYPE_NOTEBOOK_TAB);
960
  notebook_signals[SELECT_PAGE] =
961
    g_signal_new (I_("select-page"),
Manish Singh's avatar
Manish Singh committed
962
                  G_TYPE_FROM_CLASS (gobject_class),
963 964 965
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkNotebookClass, select_page),
                  NULL, NULL,
966 967
                  _gtk_marshal_BOOLEAN__BOOLEAN,
                  G_TYPE_BOOLEAN, 1,
968
                  G_TYPE_BOOLEAN);
969
  notebook_signals[CHANGE_CURRENT_PAGE] =
970
    g_signal_new (I_("change-current-page"),
Manish Singh's avatar
Manish Singh committed
971
                  G_TYPE_FROM_CLASS (gobject_class),
972 973 974
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkNotebookClass, change_current_page),
                  NULL, NULL,
975 976
                  _gtk_marshal_BOOLEAN__INT,
                  G_TYPE_BOOLEAN, 1,
977
                  G_TYPE_INT);
978
  notebook_signals[MOVE_FOCUS_OUT] =
979
    g_signal_new (I_("move-focus-out"),
Manish Singh's avatar
Manish Singh committed
980
                  G_TYPE_FROM_CLASS (gobject_class),
981 982 983 984 985 986
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkNotebookClass, move_focus_out),
                  NULL, NULL,
                  _gtk_marshal_VOID__ENUM,
                  G_TYPE_NONE, 1,
                  GTK_TYPE_DIRECTION_TYPE);
987
  notebook_signals[REORDER_TAB] =
988
    g_signal_new (I_("reorder-tab"),
989 990 991 992
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (GtkNotebookClass, reorder_tab),
                  NULL, NULL,
993 994
                  _gtk_marshal_BOOLEAN__ENUM_BOOLEAN,
                  G_TYPE_BOOLEAN, 2,
995
                  GTK_TYPE_DIRECTION_TYPE,
996
                  G_TYPE_BOOLEAN);
997
  /**
998
   * GtkNotebook::page-reordered:
999 1000 1001 1002
   * @notebook: the #GtkNotebook
   * @child: the child #GtkWidget affected
   * @page_num: the new page number for @child
   *
1003 1004
   * the ::page-reordered signal is emitted in the notebook
   * right after a page has been reordered.
1005 1006
   *
   * Since: 2.10
1007
   */
1008
  notebook_signals[PAGE_REORDERED] =
1009
    g_signal_new (I_("page-reordered"),
1010
                  G_TYPE_FROM_CLASS (gobject_class),
1011
                  G_SIGNAL_RUN_LAST,
1012 1013 1014
                  G_STRUCT_OFFSET (GtkNotebookClass, page_reordered),
                  NULL, NULL,
                  _gtk_marshal_VOID__OBJECT_UINT,
1015
                  G_TYPE_NONE, 2,
1016 1017
                  GTK_TYPE_WIDGET,
                  G_TYPE_UINT);
1018
  /**
1019
   * GtkNotebook::page-removed:
1020 1021 1022 1023
   * @notebook: the #GtkNotebook
   * @child: the child #GtkWidget affected
   * @page_num: the @child page number
   *
1024
   * the ::page-removed signal is emitted in the notebook
1025
   * right after a page is removed from the notebook.
1026 1027
   *
   * Since: 2.10
1028
   */
1029
  notebook_signals[PAGE_REMOVED] =
1030
    g_signal_new (I_("page-removed"),
1031
                  G_TYPE_FROM_CLASS (gobject_class),
1032
                  G_SIGNAL_RUN_LAST,
1033 1034 1035
                  G_STRUCT_OFFSET (GtkNotebookClass, page_removed),
                  NULL, NULL,
                  _gtk_marshal_VOID__OBJECT_UINT,
1036
                  G_TYPE_NONE, 2,
1037 1038
                  GTK_TYPE_WIDGET,
                  G_TYPE_UINT);
1039
  /**
1040
   * GtkNotebook::page-added:
1041 1042 1043 1044
   * @notebook: the #GtkNotebook
   * @child: the child #GtkWidget affected
   * @page_num: the new page number for @child
   *
1045 1046
   * the ::page-added signal is emitted in the notebook
   * right after a page is added to the notebook.
1047 1048
   *
   * Since: 2.10
1049
   */
1050
  notebook_signals[PAGE_ADDED] =
1051
    g_signal_new (I_("page-added"),
1052
                  G_TYPE_FROM_CLASS (gobject_class),
1053
                  G_SIGNAL_RUN_LAST,
1054 1055 1056
                  G_STRUCT_OFFSET (GtkNotebookClass, page_added),
                  NULL, NULL,
                  _gtk_marshal_VOID__OBJECT_UINT,
1057
                  G_TYPE_NONE, 2,
1058 1059
                  GTK_TYPE_WIDGET,
                  G_TYPE_UINT);
1060

1061 1062 1063 1064 1065 1066 1067 1068
  /**
   * GtkNotebook::create-window:
   * @notebook: the #GtkNotebook emitting the signal
   * @page: the tab of @notebook that is being detached
   * @x: the X coordinate where the drop happens
   * @y: the Y coordinate where the drop happens
   *
   * The ::create-window signal is emitted when a detachable
1069
   * tab is dropped on the root window.
1070
   *
1071 1072 1073 1074
   * A handler for this signal can create a window containing
   * a notebook where the tab will be attached. It is also
   * responsible for moving/resizing the window and adding the
   * necessary properties to the notebook (e.g. the
1075
   * #GtkNotebook:group ).
1076
   *
1077 1078
   * Returns: (transfer none): a #GtkNotebook that @page should be
   *     added to, or %NULL.
1079 1080 1081
   *
   * Since: 2.12
   */
1082
  notebook_signals[CREATE_WINDOW] =
1083
    g_signal_new (I_("create-window"),
1084 1085 1086 1087 1088 1089 1090
                  G_TYPE_FROM_CLASS (gobject_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkNotebookClass, create_window),
                  gtk_object_handled_accumulator, NULL,
                  _gtk_marshal_OBJECT__OBJECT_INT_INT,
                  GTK_TYPE_NOTEBOOK, 3,
                  GTK_TYPE_WIDGET, G_TYPE_INT, G_TYPE_INT);
1091

Manish Singh's avatar
Manish Singh committed
1092
  binding_set = gtk_binding_set_by_class (class);
1093
  gtk_binding_entry_add_signal (binding_set,
1094
                                GDK_KEY_space, 0,
1095
                                "select-page", 1,
1096
                                G_TYPE_BOOLEAN, FALSE);
1097
  gtk_binding_entry_add_signal (binding_set,
1098
                                GDK_KEY_KP_Space, 0,
1099
                                "select-page", 1,
1100
                                G_TYPE_BOOLEAN, FALSE);
1101

1102
  gtk_binding_entry_add_signal (binding_set,
1103
                                GDK_KEY_Home, 0,
1104
                                "focus-tab", 1,
1105 1106
                                GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
  gtk_binding_entry_add_signal (binding_set,
1107
                                GDK_KEY_KP_Home, 0,
1108
                                "focus-tab", 1,
1109 1110
                                GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_FIRST);
  gtk_binding_entry_add_signal (binding_set,
1111
                                GDK_KEY_End, 0,
1112
                                "focus-tab", 1,
1113 1114
                                GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
  gtk_binding_entry_add_signal (binding_set,
1115
                                GDK_KEY_KP_End, 0,
1116
                                "focus-tab", 1,
1117
                                GTK_TYPE_NOTEBOOK_TAB, GTK_NOTEBOOK_TAB_LAST);
1118 1119

  gtk_binding_entry_add_signal (binding_set,
1120
                                GDK_KEY_Page_Up, GDK_CONTROL_MASK,
1121
                                "change-current-page", 1,
1122 1123
                                G_TYPE_INT, -1);
  gtk_binding_entry_add_signal (binding_set,
1124
                                GDK_KEY_Page_Down, GDK_CONTROL_MASK,
1125
                                "change-current-page", 1,
1126
                                G_TYPE_INT, 1);
1127

1128
  gtk_binding_entry_add_signal (binding_set,
1129
                                GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1130
                                "change-current-page", 1,
1131 1132
                                G_TYPE_INT, -1);
  gtk_binding_entry_add_signal (binding_set,
1133
                                GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK,
1134
                                "change-current-page", 1,
1135 1136
                                G_TYPE_INT, 1);

1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
  add_arrow_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP);
  add_arrow_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN);
  add_arrow_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT);
  add_arrow_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT);

  add_reorder_bindings (binding_set, GDK_KEY_Up, GTK_DIR_UP, FALSE);
  add_reorder_bindings (binding_set, GDK_KEY_Down, GTK_DIR_DOWN, FALSE);
  add_reorder_bindings (binding_set, GDK_KEY_Left, GTK_DIR_LEFT, FALSE);
  add_reorder_bindings (binding_set, GDK_KEY_Right, GTK_DIR_RIGHT, FALSE);
  add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_LEFT, TRUE);
  add_reorder_bindings (binding_set, GDK_KEY_Home, GTK_DIR_UP, TRUE);
  add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_RIGHT, TRUE);
  add_reorder_bindings (binding_set, GDK_KEY_End, GTK_DIR_DOWN, TRUE);
1150

1151 1152
  add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
  add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
1153

1154
  g_type_class_add_private (class, sizeof (GtkNotebookPrivate));
Elliot Lee's avatar
Elliot Lee committed
1155 1156
}

1157
static void
1158 1159
gtk_notebook_init (GtkNotebook *notebook)
{
1160
  GtkNotebookPrivate *priv;
1161
  GtkStyleContext *context;
1162

1163
  gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
1164
  gtk_widget_set_has_window (GTK_WIDGET (notebook), FALSE);
1165

1166 1167
  notebook->priv = G_TYPE_INSTANCE_GET_PRIVATE (notebook,
                                                GTK_TYPE_NOTEBOOK,
1168
                                                GtkNotebookPrivate);
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
  priv = notebook->priv;

  priv->cur_page = NULL;
  priv->children = NULL;
  priv->first_tab = NULL;
  priv->focus_tab = NULL;
  priv->event_window = NULL;
  priv->menu = NULL;

  priv->tab_hborder = 2;
  priv->tab_vborder = 2;

  priv->show_tabs = TRUE;
  priv->show_border = TRUE;
  priv->tab_pos = GTK_POS_TOP;
  priv->scrollable = FALSE;
  priv->in_child = 0;
  priv->click_child = 0;
  priv->button = 0;
  priv->need_timer = 0;
  priv->child_has_focus = FALSE;
  priv->have_visible_child = FALSE;
  priv->focus_out = FALSE;

  priv->has_before_previous = 1;
  priv->has_before_next     = 0;
  priv->has_after_previous  = 0;
  priv->has_after_next      = 1;
1197

1198
  priv->group = 0;
1199 1200
  priv->pressed_button = -1;
  priv->dnd_timer = 0;
1201
  priv->switch_tab_timer = 0;
1202
  priv->source_targets = gtk_target_list_new (notebook_targets,
1203
                                              G_N_ELEMENTS (notebook_targets));
1204 1205 1206 1207
  priv->operation = DRAG_OPERATION_NONE;
  priv->detached_tab = NULL;
  priv->during_detach = FALSE;
  priv->has_scrolled = FALSE;
1208

1209
  gtk_drag_dest_set (GTK_WIDGET (notebook), 0,
1210
                     notebook_targets, G_N_ELEMENTS (notebook_targets),
1211
                     GDK_ACTION_MOVE);
1212 1213

  gtk_drag_dest_set_track_motion (GTK_WIDGET (notebook), TRUE);
1214 1215 1216

  context = gtk_widget_get_style_context (GTK_WIDGET (notebook));
  gtk_style_context_add_class (context,