diff options
author | Owen Taylor <otaylor@redhat.com> | 2000-12-11 17:47:24 +0000 |
---|---|---|
committer | Owen Taylor <otaylor@src.gnome.org> | 2000-12-11 17:47:24 +0000 |
commit | 0cdc00ec0b5364bcbe9b0567be64bd9efdda3074 (patch) | |
tree | 7c15c586d752ed8976d6e22492d00082fc62477a | |
parent | 5a188a9f13cd4fd4b4ae243796c92cb771313f64 (diff) | |
download | gtk+-0cdc00ec0b5364bcbe9b0567be64bd9efdda3074.tar.gz |
Add a function to determine if a window is the focus widget within its
Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function
to determine if a window is the focus widget within
its toplevel.
* gtk/gtkcontainer.[ch]: Fix the return type of ::focus
to be boolean.
* gtk/gtkcontainer.c (gtk_container_real_focus): Move handling
of the case where the container CAN_FOCUS to here instead
of having it in each individual move-the-focus place.
* gtk/gtkcontainer.c: Rewrite handling of left-right and up-down
focusing to be geometric in a much more obvious sense. Arrowing
around is still non-intuitive because it isn't perfect and
because entries, etc, grab the arrow keys, but it at least
usually will do what you expect now.
* gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this
file.
* gtk/gtknotebook.c: Change tabs to be a single item in
the focus chain. Make movement of focus on tabs with arrow
keys wrap around.
* gtk/gtknotebook.c (gtk_notebook_find_child): Add
CHECK_FIND_CHILD macro to give informative error messages
instead of silent returns.
* gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT
flag since we handle GdkReturn on the tabs.
* gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate
windows rather than sending expose events directly.
* gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure
definition for GtkNotebookPage into .c file, since it is private.
* gtk/testgtk.c (create_notebook): Add option for
testing borderless notebook.
* gtk/testgtk.c (page_switch): Removed egregious poking
around in GTK+ internals.
* docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING.
* gtk/gtkclist.[ch]: Remove key press handler, handle focusing
properly through gtk_clist_focus. Make the title headers a
single item in the tab-focus chain, and make left-right wrap
around.
* gtk/gtkwindow.c (gtk_window_focus): Add a custom
focus method so that wrapping around works properly.
* gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() -
that is handled for the widget now.
-rw-r--r-- | ChangeLog | 59 | ||||
-rw-r--r-- | ChangeLog.pre-2-0 | 59 | ||||
-rw-r--r-- | ChangeLog.pre-2-10 | 59 | ||||
-rw-r--r-- | ChangeLog.pre-2-2 | 59 | ||||
-rw-r--r-- | ChangeLog.pre-2-4 | 59 | ||||
-rw-r--r-- | ChangeLog.pre-2-6 | 59 | ||||
-rw-r--r-- | ChangeLog.pre-2-8 | 59 | ||||
-rw-r--r-- | docs/Changes-2.0.txt | 4 | ||||
-rw-r--r-- | docs/reference/ChangeLog | 5 | ||||
-rw-r--r-- | docs/reference/gtk/tmpl/gtknotebook.sgml | 279 | ||||
-rw-r--r-- | docs/widget_system.txt | 11 | ||||
-rw-r--r-- | gtk/gtkclist.c | 401 | ||||
-rw-r--r-- | gtk/gtkclist.h | 5 | ||||
-rw-r--r-- | gtk/gtkcontainer.c | 484 | ||||
-rw-r--r-- | gtk/gtkcontainer.h | 24 | ||||
-rw-r--r-- | gtk/gtknotebook.c | 1233 | ||||
-rw-r--r-- | gtk/gtknotebook.h | 39 | ||||
-rw-r--r-- | gtk/gtktreeview.c | 23 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 26 | ||||
-rw-r--r-- | gtk/gtkwidget.h | 1 | ||||
-rw-r--r-- | gtk/gtkwindow.c | 57 | ||||
-rw-r--r-- | gtk/testgtk.c | 70 | ||||
-rw-r--r-- | tests/testgtk.c | 70 |
23 files changed, 1979 insertions, 1166 deletions
@@ -1,3 +1,61 @@ +Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function + to determine if a window is the focus widget within + its toplevel. + + * gtk/gtkcontainer.[ch]: Fix the return type of ::focus + to be boolean. + + * gtk/gtkcontainer.c (gtk_container_real_focus): Move handling + of the case where the container CAN_FOCUS to here instead + of having it in each individual move-the-focus place. + + * gtk/gtkcontainer.c: Rewrite handling of left-right and up-down + focusing to be geometric in a much more obvious sense. Arrowing + around is still non-intuitive because it isn't perfect and + because entries, etc, grab the arrow keys, but it at least + usually will do what you expect now. + + * gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this + file. + + * gtk/gtknotebook.c: Change tabs to be a single item in + the focus chain. Make movement of focus on tabs with arrow + keys wrap around. + + * gtk/gtknotebook.c (gtk_notebook_find_child): Add + CHECK_FIND_CHILD macro to give informative error messages + instead of silent returns. + + * gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT + flag since we handle GdkReturn on the tabs. + + * gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate + windows rather than sending expose events directly. + + * gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure + definition for GtkNotebookPage into .c file, since it is private. + + * gtk/testgtk.c (create_notebook): Add option for + testing borderless notebook. + + * gtk/testgtk.c (page_switch): Removed egregious poking + around in GTK+ internals. + + * docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING. + + * gtk/gtkclist.[ch]: Remove key press handler, handle focusing + properly through gtk_clist_focus. Make the title headers a + single item in the tab-focus chain, and make left-right wrap + around. + + * gtk/gtkwindow.c (gtk_window_focus): Add a custom + focus method so that wrapping around works properly. + + * gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() - + that is handled for the widget now. + Mon Dec 11 11:41:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtkinvisible.c (gtk_invisible_init): Flag invisible @@ -149,6 +207,7 @@ Mon Dec 11 10:02:26 2000 Owen Taylor <otaylor@redhat.com> 2000-12-06 Elliot Lee <sopwith@redhat.com> * configure.in: Detect freetype properly + * modules/basic/Makefile.am, gdk/linux-fb/Makefile.am: Make use of above. diff --git a/ChangeLog.pre-2-0 b/ChangeLog.pre-2-0 index d951aa6465..b43810e866 100644 --- a/ChangeLog.pre-2-0 +++ b/ChangeLog.pre-2-0 @@ -1,3 +1,61 @@ +Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function + to determine if a window is the focus widget within + its toplevel. + + * gtk/gtkcontainer.[ch]: Fix the return type of ::focus + to be boolean. + + * gtk/gtkcontainer.c (gtk_container_real_focus): Move handling + of the case where the container CAN_FOCUS to here instead + of having it in each individual move-the-focus place. + + * gtk/gtkcontainer.c: Rewrite handling of left-right and up-down + focusing to be geometric in a much more obvious sense. Arrowing + around is still non-intuitive because it isn't perfect and + because entries, etc, grab the arrow keys, but it at least + usually will do what you expect now. + + * gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this + file. + + * gtk/gtknotebook.c: Change tabs to be a single item in + the focus chain. Make movement of focus on tabs with arrow + keys wrap around. + + * gtk/gtknotebook.c (gtk_notebook_find_child): Add + CHECK_FIND_CHILD macro to give informative error messages + instead of silent returns. + + * gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT + flag since we handle GdkReturn on the tabs. + + * gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate + windows rather than sending expose events directly. + + * gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure + definition for GtkNotebookPage into .c file, since it is private. + + * gtk/testgtk.c (create_notebook): Add option for + testing borderless notebook. + + * gtk/testgtk.c (page_switch): Removed egregious poking + around in GTK+ internals. + + * docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING. + + * gtk/gtkclist.[ch]: Remove key press handler, handle focusing + properly through gtk_clist_focus. Make the title headers a + single item in the tab-focus chain, and make left-right wrap + around. + + * gtk/gtkwindow.c (gtk_window_focus): Add a custom + focus method so that wrapping around works properly. + + * gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() - + that is handled for the widget now. + Mon Dec 11 11:41:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtkinvisible.c (gtk_invisible_init): Flag invisible @@ -149,6 +207,7 @@ Mon Dec 11 10:02:26 2000 Owen Taylor <otaylor@redhat.com> 2000-12-06 Elliot Lee <sopwith@redhat.com> * configure.in: Detect freetype properly + * modules/basic/Makefile.am, gdk/linux-fb/Makefile.am: Make use of above. diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index d951aa6465..b43810e866 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,61 @@ +Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function + to determine if a window is the focus widget within + its toplevel. + + * gtk/gtkcontainer.[ch]: Fix the return type of ::focus + to be boolean. + + * gtk/gtkcontainer.c (gtk_container_real_focus): Move handling + of the case where the container CAN_FOCUS to here instead + of having it in each individual move-the-focus place. + + * gtk/gtkcontainer.c: Rewrite handling of left-right and up-down + focusing to be geometric in a much more obvious sense. Arrowing + around is still non-intuitive because it isn't perfect and + because entries, etc, grab the arrow keys, but it at least + usually will do what you expect now. + + * gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this + file. + + * gtk/gtknotebook.c: Change tabs to be a single item in + the focus chain. Make movement of focus on tabs with arrow + keys wrap around. + + * gtk/gtknotebook.c (gtk_notebook_find_child): Add + CHECK_FIND_CHILD macro to give informative error messages + instead of silent returns. + + * gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT + flag since we handle GdkReturn on the tabs. + + * gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate + windows rather than sending expose events directly. + + * gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure + definition for GtkNotebookPage into .c file, since it is private. + + * gtk/testgtk.c (create_notebook): Add option for + testing borderless notebook. + + * gtk/testgtk.c (page_switch): Removed egregious poking + around in GTK+ internals. + + * docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING. + + * gtk/gtkclist.[ch]: Remove key press handler, handle focusing + properly through gtk_clist_focus. Make the title headers a + single item in the tab-focus chain, and make left-right wrap + around. + + * gtk/gtkwindow.c (gtk_window_focus): Add a custom + focus method so that wrapping around works properly. + + * gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() - + that is handled for the widget now. + Mon Dec 11 11:41:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtkinvisible.c (gtk_invisible_init): Flag invisible @@ -149,6 +207,7 @@ Mon Dec 11 10:02:26 2000 Owen Taylor <otaylor@redhat.com> 2000-12-06 Elliot Lee <sopwith@redhat.com> * configure.in: Detect freetype properly + * modules/basic/Makefile.am, gdk/linux-fb/Makefile.am: Make use of above. diff --git a/ChangeLog.pre-2-2 b/ChangeLog.pre-2-2 index d951aa6465..b43810e866 100644 --- a/ChangeLog.pre-2-2 +++ b/ChangeLog.pre-2-2 @@ -1,3 +1,61 @@ +Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function + to determine if a window is the focus widget within + its toplevel. + + * gtk/gtkcontainer.[ch]: Fix the return type of ::focus + to be boolean. + + * gtk/gtkcontainer.c (gtk_container_real_focus): Move handling + of the case where the container CAN_FOCUS to here instead + of having it in each individual move-the-focus place. + + * gtk/gtkcontainer.c: Rewrite handling of left-right and up-down + focusing to be geometric in a much more obvious sense. Arrowing + around is still non-intuitive because it isn't perfect and + because entries, etc, grab the arrow keys, but it at least + usually will do what you expect now. + + * gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this + file. + + * gtk/gtknotebook.c: Change tabs to be a single item in + the focus chain. Make movement of focus on tabs with arrow + keys wrap around. + + * gtk/gtknotebook.c (gtk_notebook_find_child): Add + CHECK_FIND_CHILD macro to give informative error messages + instead of silent returns. + + * gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT + flag since we handle GdkReturn on the tabs. + + * gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate + windows rather than sending expose events directly. + + * gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure + definition for GtkNotebookPage into .c file, since it is private. + + * gtk/testgtk.c (create_notebook): Add option for + testing borderless notebook. + + * gtk/testgtk.c (page_switch): Removed egregious poking + around in GTK+ internals. + + * docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING. + + * gtk/gtkclist.[ch]: Remove key press handler, handle focusing + properly through gtk_clist_focus. Make the title headers a + single item in the tab-focus chain, and make left-right wrap + around. + + * gtk/gtkwindow.c (gtk_window_focus): Add a custom + focus method so that wrapping around works properly. + + * gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() - + that is handled for the widget now. + Mon Dec 11 11:41:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtkinvisible.c (gtk_invisible_init): Flag invisible @@ -149,6 +207,7 @@ Mon Dec 11 10:02:26 2000 Owen Taylor <otaylor@redhat.com> 2000-12-06 Elliot Lee <sopwith@redhat.com> * configure.in: Detect freetype properly + * modules/basic/Makefile.am, gdk/linux-fb/Makefile.am: Make use of above. diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index d951aa6465..b43810e866 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,61 @@ +Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function + to determine if a window is the focus widget within + its toplevel. + + * gtk/gtkcontainer.[ch]: Fix the return type of ::focus + to be boolean. + + * gtk/gtkcontainer.c (gtk_container_real_focus): Move handling + of the case where the container CAN_FOCUS to here instead + of having it in each individual move-the-focus place. + + * gtk/gtkcontainer.c: Rewrite handling of left-right and up-down + focusing to be geometric in a much more obvious sense. Arrowing + around is still non-intuitive because it isn't perfect and + because entries, etc, grab the arrow keys, but it at least + usually will do what you expect now. + + * gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this + file. + + * gtk/gtknotebook.c: Change tabs to be a single item in + the focus chain. Make movement of focus on tabs with arrow + keys wrap around. + + * gtk/gtknotebook.c (gtk_notebook_find_child): Add + CHECK_FIND_CHILD macro to give informative error messages + instead of silent returns. + + * gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT + flag since we handle GdkReturn on the tabs. + + * gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate + windows rather than sending expose events directly. + + * gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure + definition for GtkNotebookPage into .c file, since it is private. + + * gtk/testgtk.c (create_notebook): Add option for + testing borderless notebook. + + * gtk/testgtk.c (page_switch): Removed egregious poking + around in GTK+ internals. + + * docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING. + + * gtk/gtkclist.[ch]: Remove key press handler, handle focusing + properly through gtk_clist_focus. Make the title headers a + single item in the tab-focus chain, and make left-right wrap + around. + + * gtk/gtkwindow.c (gtk_window_focus): Add a custom + focus method so that wrapping around works properly. + + * gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() - + that is handled for the widget now. + Mon Dec 11 11:41:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtkinvisible.c (gtk_invisible_init): Flag invisible @@ -149,6 +207,7 @@ Mon Dec 11 10:02:26 2000 Owen Taylor <otaylor@redhat.com> 2000-12-06 Elliot Lee <sopwith@redhat.com> * configure.in: Detect freetype properly + * modules/basic/Makefile.am, gdk/linux-fb/Makefile.am: Make use of above. diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index d951aa6465..b43810e866 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,61 @@ +Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function + to determine if a window is the focus widget within + its toplevel. + + * gtk/gtkcontainer.[ch]: Fix the return type of ::focus + to be boolean. + + * gtk/gtkcontainer.c (gtk_container_real_focus): Move handling + of the case where the container CAN_FOCUS to here instead + of having it in each individual move-the-focus place. + + * gtk/gtkcontainer.c: Rewrite handling of left-right and up-down + focusing to be geometric in a much more obvious sense. Arrowing + around is still non-intuitive because it isn't perfect and + because entries, etc, grab the arrow keys, but it at least + usually will do what you expect now. + + * gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this + file. + + * gtk/gtknotebook.c: Change tabs to be a single item in + the focus chain. Make movement of focus on tabs with arrow + keys wrap around. + + * gtk/gtknotebook.c (gtk_notebook_find_child): Add + CHECK_FIND_CHILD macro to give informative error messages + instead of silent returns. + + * gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT + flag since we handle GdkReturn on the tabs. + + * gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate + windows rather than sending expose events directly. + + * gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure + definition for GtkNotebookPage into .c file, since it is private. + + * gtk/testgtk.c (create_notebook): Add option for + testing borderless notebook. + + * gtk/testgtk.c (page_switch): Removed egregious poking + around in GTK+ internals. + + * docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING. + + * gtk/gtkclist.[ch]: Remove key press handler, handle focusing + properly through gtk_clist_focus. Make the title headers a + single item in the tab-focus chain, and make left-right wrap + around. + + * gtk/gtkwindow.c (gtk_window_focus): Add a custom + focus method so that wrapping around works properly. + + * gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() - + that is handled for the widget now. + Mon Dec 11 11:41:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtkinvisible.c (gtk_invisible_init): Flag invisible @@ -149,6 +207,7 @@ Mon Dec 11 10:02:26 2000 Owen Taylor <otaylor@redhat.com> 2000-12-06 Elliot Lee <sopwith@redhat.com> * configure.in: Detect freetype properly + * modules/basic/Makefile.am, gdk/linux-fb/Makefile.am: Make use of above. diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index d951aa6465..b43810e866 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,61 @@ +Wed Oct 25 14:17:43 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/gtkwidget.[ch] (gtk_widget_is_focus): Add a function + to determine if a window is the focus widget within + its toplevel. + + * gtk/gtkcontainer.[ch]: Fix the return type of ::focus + to be boolean. + + * gtk/gtkcontainer.c (gtk_container_real_focus): Move handling + of the case where the container CAN_FOCUS to here instead + of having it in each individual move-the-focus place. + + * gtk/gtkcontainer.c: Rewrite handling of left-right and up-down + focusing to be geometric in a much more obvious sense. Arrowing + around is still non-intuitive because it isn't perfect and + because entries, etc, grab the arrow keys, but it at least + usually will do what you expect now. + + * gtk/gtknotebook.[ch]: Many cleanups. Moved docs inline in this + file. + + * gtk/gtknotebook.c: Change tabs to be a single item in + the focus chain. Make movement of focus on tabs with arrow + keys wrap around. + + * gtk/gtknotebook.c (gtk_notebook_find_child): Add + CHECK_FIND_CHILD macro to give informative error messages + instead of silent returns. + + * gtk/gtknotebook.c (gtk_notebook_init): Set the RECEIVES_DEFAULT + flag since we handle GdkReturn on the tabs. + + * gtk/gtknotebook.c (gtk_notebook_expose_tabs): Invalidate + windows rather than sending expose events directly. + + * gtk/gtknotebook.[ch] docs/Changes-2.0.txt: Move structure + definition for GtkNotebookPage into .c file, since it is private. + + * gtk/testgtk.c (create_notebook): Add option for + testing borderless notebook. + + * gtk/testgtk.c (page_switch): Removed egregious poking + around in GTK+ internals. + + * docs/widget-system.txt: Remove references to GTK_REDRAW_PENDING. + + * gtk/gtkclist.[ch]: Remove key press handler, handle focusing + properly through gtk_clist_focus. Make the title headers a + single item in the tab-focus chain, and make left-right wrap + around. + + * gtk/gtkwindow.c (gtk_window_focus): Add a custom + focus method so that wrapping around works properly. + + * gtk/gtktreeview.c: Remove calls to gtk_container_set_focus_child() - + that is handled for the widget now. + Mon Dec 11 11:41:12 2000 Owen Taylor <otaylor@redhat.com> * gtk/gtkinvisible.c (gtk_invisible_init): Flag invisible @@ -149,6 +207,7 @@ Mon Dec 11 10:02:26 2000 Owen Taylor <otaylor@redhat.com> 2000-12-06 Elliot Lee <sopwith@redhat.com> * configure.in: Detect freetype properly + * modules/basic/Makefile.am, gdk/linux-fb/Makefile.am: Make use of above. diff --git a/docs/Changes-2.0.txt b/docs/Changes-2.0.txt index 50877024bc..0c5789f39d 100644 --- a/docs/Changes-2.0.txt +++ b/docs/Changes-2.0.txt @@ -255,6 +255,10 @@ Incompatible Changes from GTK+-1.2 to GTK+-2.0: void gtk_progress_bar_set_orientation (GtkProgressBar *pbar, GtkProgressBarOrientation orientation); +* The GtkNotebookPage structure has been removed from the public header files; + this was never meant to be a public structure, and all functionality that + could be done by accessing the struct fields of this structure should be + accesible otherwise. - GtkMenuPositionFunc has a new parameter push_in which controls how menus placed outside the screen is handled. If this is set to true and diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog index 96b66d7d1c..e2bbb8bced 100644 --- a/docs/reference/ChangeLog +++ b/docs/reference/ChangeLog @@ -1,3 +1,8 @@ +Wed Oct 25 15:19:40 2000 Owen Taylor <otaylor@redhat.com> + + * gtk/tmpl/gtknotebook.sgml: Moved function docs into .c + file, fairly extensive rewriting. + Thu Nov 30 00:53:45 2000 Owen Taylor <otaylor@redhat.com> * gtk/tmpl/gtkfilesel.sgml: Fix to say that file_selection_complete() diff --git a/docs/reference/gtk/tmpl/gtknotebook.sgml b/docs/reference/gtk/tmpl/gtknotebook.sgml index 4b73f7b5d1..a51536f49d 100644 --- a/docs/reference/gtk/tmpl/gtknotebook.sgml +++ b/docs/reference/gtk/tmpl/gtknotebook.sgml @@ -2,13 +2,21 @@ GtkNotebook <!-- ##### SECTION Short_Description ##### --> -Set of pages with bookmarks. +A tabbed notebook container. <!-- ##### SECTION Long_Description ##### --> <para> The #GtkNotebook widget is a #GtkContainer whose children are pages that -can be accessed through bookmarks. The pages are displayed all at the same -place. <!-- TODO: talk about the menu --> +can be switched between using tab labels along one edge. +</para> +<para> +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 noteobook 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_enable_popup(), gtk_noteobook_disable_popup()) </para> <!-- ##### SECTION See_Also ##### --> @@ -28,124 +36,83 @@ place. <!-- TODO: talk about the menu --> </para> -<!-- ##### MACRO GTK_NOTEBOOK_PAGE ##### --> -<para> -Extracts the contents of the current element of #GList @_glist_ as a -#GtkNotebookPage. -</para> - -@_glist_: - - <!-- ##### STRUCT GtkNotebookPage ##### --> <para> -The #GtkNotebookPage structure is used to store the pages of a notebook. It -is not an object. +The #GtkNotebookPage is an opaque implementation detail of #GtkNotebook. </para> -@child: the contents of the page -@tab_label: the label shown in the bookmark -@menu_label: the label shown in the popup menu -@default_menu: -@default_tab: -@expand: -@fill: -@pack: -@requisition: -@allocation: - <!-- ##### FUNCTION gtk_notebook_new ##### --> <para> -Creates a new #GtkNotebook widget </para> -@Returns: the newly created G=#GtkNotebook +@Returns: <!-- ##### FUNCTION gtk_notebook_append_page ##### --> <para> -Appends to @notebook a page whose content is @child, and whose bookmark is -@tab_label. </para> -@notebook: the notebook widget -@child: the content of the new page -@tab_label: the bookmark for the page +@notebook: +@child: +@tab_label: <!-- ##### FUNCTION gtk_notebook_append_page_menu ##### --> <para> -Appends to @notebook a page whose content is @child, whose bookmark is -@tab_label, and whose menu label is @menu_label. </para> -@notebook: the notebook widget -@child: the content of the new page -@tab_label: the bookmark of the page -@menu_label: the menu label of the page +@notebook: +@child: +@tab_label: +@menu_label: <!-- ##### FUNCTION gtk_notebook_prepend_page ##### --> <para> -Prepends to @notebook a page whose content is @child, whose bookmark is -@tab_label, and whose menu label is @menu_label. </para> -@notebook: the notebook widget -@child: the content of the new page -@tab_label: the bookmark of the page +@notebook: +@child: the +@tab_label: <!-- ##### FUNCTION gtk_notebook_prepend_page_menu ##### --> <para> -Appends to @notebook a page whose content is @child, whose bookmark is -@tab_label, and whose menu label is @menu_label. </para> -@notebook: the notebook widget -@child: the content of the new page -@tab_label: the bookmark of the page -@menu_label: the menu label of the page +@notebook: +@child: +@tab_label: +@menu_label: <!-- ##### FUNCTION gtk_notebook_insert_page ##### --> <para> -Inserts in @notebook a new page whose content is @child, and whose -bookmark is @tab_label. The page is inserted just -before the page number @position, starting with 0. If @position is out of -bounds, it is assumed to be the current number of pages. </para> -@notebook: the notebook widget -@child: the content of the new page -@tab_label: the bookmark of the page -@position: the position to insert the page +@notebook: +@child: +@tab_label: +@position: <!-- ##### FUNCTION gtk_notebook_insert_page_menu ##### --> <para> -Inserts in @notebook a new page whose content is @child, whose bookmark is -@tab_label, and whose menu label is @menu_label. The page is inserted just -before the page number @position, starting with 0. If @position is out of -bounds, it is assumed to be the current number of pages. </para> -@notebook: the notebook widget -@child: the content of the new page -@tab_label: the bookmark of the page -@menu_label: the menu label of the page -@position: the position to insert the page +@notebook: +@child: +@tab_label: +@menu_label: +@position: <!-- ##### FUNCTION gtk_notebook_remove_page ##### --> <para> -Removes the page @page_num form @notebook. Pages are numbered starting at -zero. Negative values stand for the last page; too large values are -ignored. </para> -@notebook: the notebook widget -@page_num: the page number +@notebook: +@page_num: <!-- ##### MACRO gtk_notebook_current_page ##### --> @@ -157,56 +124,45 @@ Compatibility macro; in gtkcompat.h. <!-- ##### FUNCTION gtk_notebook_page_num ##### --> <para> -Returns the page number of @child in @notebook. </para> -@notebook: the notebook widget -@child: the child -@Returns: the page number, or -1 if @child is not in @notebook +@notebook: +@child: +@Returns: <!-- ##### FUNCTION gtk_notebook_set_page ##### --> <para> -Switches to the page number @page_num. Negative values stand for the last -page; too large values are ignored. </para> -@notebook: the notebook widget -@page_num: the page number +@notebook: +@page_num: <!-- ##### FUNCTION gtk_notebook_next_page ##### --> <para> -Switches to the next page. Nothing happens if the current page is the last -page. </para> -@notebook: the notebook widget. +@notebook: <!-- ##### FUNCTION gtk_notebook_prev_page ##### --> <para> -Switches to the previous page. Nothing happens if the current page is the -first page. </para> -@notebook: the notebook widget +@notebook: <!-- ##### FUNCTION gtk_notebook_reorder_child ##### --> <para> -Moves the page @child, so that it appears in position @position. Out of -bounds @position will be clamped. </para> -@notebook: the notebook widget -@child: the child to deplace -@position: the new position - +@notebook +@child: +@position: <!-- ##### FUNCTION gtk_notebook_set_tab_pos ##### --> <para> -Sets the position of the bookmarks. </para> @notebook: the notebook widget @@ -215,62 +171,51 @@ Sets the position of the bookmarks. <!-- ##### FUNCTION gtk_notebook_set_show_tabs ##### --> <para> -Sets whether to show the bookmarks or not. </para> -@notebook: the notebook widget -@show_tabs: a boolean value +@notebook: +@show_tabs: <!-- ##### FUNCTION gtk_notebook_set_show_border ##### --> <para> -Sets whether to show the border of the notebook or not. Bookmarks are in the -border. </para> -@notebook: the notebook widget -@show_border: a boolean value +@notebook: +@show_border: <!-- ##### FUNCTION gtk_notebook_set_scrollable ##### --> <para> -Sets whether the bookmarks area may be scrollable or not if there are too -many bookmarks to fit in the allocated area. </para> -@notebook: the notebook widget -@scrollable: a boolean value +@notebook: +@scrollable: <!-- ##### FUNCTION gtk_notebook_set_tab_border ##### --> <para> -Sets whether there should be a border around the bookmarks or not. </para> -@notebook: the notebook widget -@border_width: a boolean value +@notebook: +@border_width: <!-- ##### FUNCTION gtk_notebook_popup_enable ##### --> <para> -Enables the popup menu: if the user clicks with the right mouse button on -the bookmarks, a menu with all the pages will be popped up. </para> -@notebook: the notebook widget +@notebook: <!-- ##### FUNCTION gtk_notebook_popup_disable ##### --> <para> -Disables the popup menu </para> -@notebook: the notebook widget - +@notebook: <!-- ##### FUNCTION gtk_notebook_get_current_page ##### --> <para> -Returns the page number of the current page. </para> @notebook: the notebook widget @@ -279,129 +224,108 @@ Returns the page number of the current page. <!-- ##### FUNCTION gtk_notebook_get_menu_label ##### --> <para> -Returns the menu label of the page @child. NULL is returned if @child is not -in @notebook or NULL if it has the default menu label. </para> -@notebook: the notebook widget -@child: the page -@Returns: the menu label +@notebook: +@child: +@Returns: <!-- ##### FUNCTION gtk_notebook_get_nth_page ##### --> <para> -Returns the content of the page number @page_num, or NULL if @page_num is -out of bounds. </para> -@notebook: the notebook widget -@page_num: the page number -@Returns: the content of the page +@notebook: +@page_num: +@Returns: <!-- ##### FUNCTION gtk_notebook_get_tab_label ##### --> <para> -Returns the menu tab of the page @child. NULL is returned if @child is not -in @notebook or NULL if it has the default tab label. </para> -@notebook: the notebook widget -@child: the page -@Returns: the tab label +@notebook: +@child: +@Returns: <!-- ##### FUNCTION gtk_notebook_query_tab_label_packing ##### --> <para> -Looks for the packing attributes of the bookmarks of @child. </para> -@notebook: the notebook widget -@child: the page -@expand: a pointer to return the expand value (or NULL) -@fill: a pointer to return the fill value (or NULL) -@pack_type: a pointer to return the pack_type (or NULL) +@notebook: +@child: +@expand: +@fill: +@pack_type: <!-- ##### FUNCTION gtk_notebook_set_homogeneous_tabs ##### --> <para> -Sets whether the tabs must have all the same size or not. </para> -@notebook: the notebook widget -@homogeneous: a boolean value +@notebook: +@homogeneous: <!-- ##### FUNCTION gtk_notebook_set_menu_label ##### --> <para> -Changes the menu label of @child. Nothing happens if @child is not in -@notebook. </para> -@notebook: the notebook widget -@child: the page -@menu_label: the menu label, or NULL for default +@notebook: +@child: +@menu_label: <!-- ##### FUNCTION gtk_notebook_set_menu_label_text ##### --> <para> -Creates a new label and sets it as the menu label of @child. </para> -@notebook: the notebook widget -@child: the page -@menu_text: the label text <!-- ##### FUNCTION gtk_notebook_set_tab_hborder ##### --> <para> -Sets whether the tabs should have a horizontal border. </para> -@notebook: the notebook widget -@tab_hborder: a boolean value +@notebook: +@tab_hborder: <!-- ##### FUNCTION gtk_notebook_set_tab_label ##### --> <para> -Changes the bookmark label of @child. Nothing happens if @child is not in -@notebook. </para> -@notebook: the notebook widget -@child: the page -@tab_label: the bookmark label, or NULL for default +@notebook: +@child: +@tab_label: <!-- ##### FUNCTION gtk_notebook_set_tab_label_packing ##### --> <para> -Sets the packing parameters for the bookmark of @child. See -#GtkBoxPackStart for the exact meanings. </para> -@notebook: the notebook widget -@child: the child widget -@expand: whether to expand the bookmark or not -@fill: whether the bookmark should fill the allocated area or not -@pack_type: the position of the bookmark +@notebook: +@child: +@expand: +@fill: +@pack_type: <!-- ##### FUNCTION gtk_notebook_set_tab_label_text ##### --> <para> -Creates a new label and sets it as the bookmark label of @child. </para> -@notebook: the notebook widget -@child: the page -@tab_text: the label text +@notebook: +@child: +@tab_text: <!-- ##### FUNCTION gtk_notebook_set_tab_vborder ##### --> <para> -Sets whether the tabs should have a vertical border. </para> -@notebook: the notebook widget -@tab_vborder: a boolean value +@notebook: +@tab_vborder: <!-- ##### SIGNAL GtkNotebook::switch-page ##### --> @@ -420,46 +344,47 @@ The current page <!-- ##### ARG GtkNotebook:tab_pos ##### --> <para> -The position of the bookmarks +The edge at which the tabs for switching pages are drawn. </para> <!-- ##### ARG GtkNotebook:tab_border ##### --> <para> -Whether the bookmarks have a border or not +Whether the tab labels have a border on all sides. </para> <!-- ##### ARG GtkNotebook:tab_hborder ##### --> <para> -Whether the bookmarks have a horizontal border or not +Whether the tab labels have a horizontal border. </para> <!-- ##### ARG GtkNotebook:tab_vborder ##### --> <para> -Whether the bookmarks have a vertical border or not +Whether the tab labels have a vertical border. </para> <!-- ##### ARG GtkNotebook:show_tabs ##### --> <para> -Whether to show the bookmarks or not +Whether to show tabs for the notebook pages. </para> <!-- ##### ARG GtkNotebook:show_border ##### --> <para> -Whether to show the border or not +Whether to draw a bevel around the noteobook. </para> <!-- ##### ARG GtkNotebook:scrollable ##### --> <para> -Whether the bookmarks should be scrollable or not +Whether the tab label area will have arrows for scrolling if there +are too many tabs to fit in the area. </para> <!-- ##### ARG GtkNotebook:enable_popup ##### --> <para> -Whether the popup menu is enabled or not +Whether the popup menu for switching pages is enabled. </para> <!-- ##### ARG GtkNotebook:homogeneous ##### --> <para> - +whether the tabs must have all the same size. </para> diff --git a/docs/widget_system.txt b/docs/widget_system.txt index 07a5532db6..1c6428af11 100644 --- a/docs/widget_system.txt +++ b/docs/widget_system.txt @@ -150,15 +150,6 @@ GTK_USER_STYLE: wich share a global user style from the ones which got a certain style assign from outside the toolkit. -GTK_REDRAW_PENDING: - Relies on GTK_WIDGET_MAPPED (widget). - [FIXME: this is not really enforced throughout the code, but should - be. it only requires a few checks for GTK_WIDGET_MAPPED and - minor changes to gtk_widget_unmap, we can then remove the check - in gtk_widget_real_destroy] - Means: there is an idle handler waiting for the widget, that - will cause a full redraw (gtk_widget_draw (widget, NULL)). - GTK_RESIZE_PENDING: First, this is only valid for GtkContainers. [some of the code should move to gtkcontainer.c therefore] @@ -245,7 +236,7 @@ In the following Note:, the definition [ GTK_WIDGET_DRAWABLE = GTK_WIDGET_VISIBLE && GTK_WIDGET_MAPPED - is made in gtkwidget.c, but by 3) and 5), + is made in gtkwidget.h, but by 3) and 5), GTK_WIDGET_MAPPED => GTK_WIDGET_VISIBLE ] diff --git a/gtk/gtkclist.c b/gtk/gtkclist.c index 8d83c47f1b..ab5ca5edfa 100644 --- a/gtk/gtkclist.c +++ b/gtk/gtkclist.c @@ -198,8 +198,6 @@ static void gtk_clist_map (GtkWidget *widget); static void gtk_clist_unmap (GtkWidget *widget); static gint gtk_clist_expose (GtkWidget *widget, GdkEventExpose *event); -static gint gtk_clist_key_press (GtkWidget *widget, - GdkEventKey *event); static gint gtk_clist_button_press (GtkWidget *widget, GdkEventButton *event); static gint gtk_clist_button_release (GtkWidget *widget, @@ -217,6 +215,8 @@ static gint gtk_clist_focus_out (GtkWidget *widget, GdkEventFocus *event); static gint gtk_clist_focus (GtkContainer *container, GtkDirectionType direction); +static void gtk_clist_set_focus_child (GtkContainer *container, + GtkWidget *child); static void gtk_clist_style_set (GtkWidget *widget, GtkStyle *previous_style); static void gtk_clist_drag_begin (GtkWidget *widget, @@ -250,8 +250,6 @@ static void gtk_clist_drag_data_received (GtkWidget *widget, guint time); /* GtkContainer Methods */ -static void gtk_clist_set_focus_child (GtkContainer *container, - GtkWidget *child); static void gtk_clist_forall (GtkContainer *container, gboolean include_internals, GtkCallback callback, @@ -438,8 +436,11 @@ static GList *gtk_clist_mergesort (GtkCList *clist, GList *list, gint num); /* Misc */ -static gboolean title_focus (GtkCList *clist, - gint dir); +static gboolean title_focus_in (GtkCList *clist, + gint dir); +static gboolean title_focus_move (GtkCList *clist, + gint dir); + static void real_row_move (GtkCList *clist, gint source_row, gint dest_row); @@ -675,7 +676,6 @@ gtk_clist_class_init (GtkCListClass *klass) widget_class->expose_event = gtk_clist_expose; widget_class->size_request = gtk_clist_size_request; widget_class->size_allocate = gtk_clist_size_allocate; - widget_class->key_press_event = gtk_clist_key_press; widget_class->focus_in_event = gtk_clist_focus_in; widget_class->focus_out_event = gtk_clist_focus_out; widget_class->draw_focus = gtk_clist_draw_focus; @@ -921,7 +921,6 @@ gtk_clist_init (GtkCList *clist) GTK_WIDGET_UNSET_FLAGS (clist, GTK_NO_WINDOW); GTK_WIDGET_SET_FLAGS (clist, GTK_CAN_FOCUS); - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); GTK_CLIST_SET_FLAG (clist, CLIST_DRAW_DRAG_LINE); GTK_CLIST_SET_FLAG (clist, CLIST_USE_DRAG_ICONS); @@ -973,6 +972,7 @@ gtk_clist_init (GtkCList *clist) clist->undo_unselection = NULL; clist->focus_row = -1; + clist->focus_header_column = -1; clist->undo_anchor = -1; clist->anchor = -1; @@ -4425,7 +4425,6 @@ gtk_clist_finalize (GObject *object) * gtk_clist_unmap * gtk_clist_expose * gtk_clist_style_set - * gtk_clist_key_press * gtk_clist_button_press * gtk_clist_button_release * gtk_clist_motion @@ -4466,7 +4465,6 @@ gtk_clist_realize (GtkWidget *widget) attributes.event_mask |= (GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK); attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; @@ -4524,8 +4522,7 @@ gtk_clist_realize (GtkWidget *widget) attributes.event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_KEY_PRESS_MASK); + GDK_POINTER_MOTION_HINT_MASK); attributes_mask = GDK_WA_CURSOR; attributes.cursor = gdk_cursor_new (GDK_SB_H_DOUBLE_ARROW); clist->cursor_drag = attributes.cursor; @@ -4842,34 +4839,6 @@ gtk_clist_style_set (GtkWidget *widget, } static gint -gtk_clist_key_press (GtkWidget *widget, - GdkEventKey *event) -{ - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); - - if (GTK_WIDGET_CLASS (parent_class)->key_press_event && - GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event)) - return TRUE; - - switch (event->keyval) - { - case GDK_Tab: - case GDK_ISO_Left_Tab: - if (event->state & GDK_SHIFT_MASK) - return gtk_container_focus (GTK_CONTAINER (widget), - GTK_DIR_TAB_BACKWARD); - else - return gtk_container_focus (GTK_CONTAINER (widget), - GTK_DIR_TAB_FORWARD); - default: - break; - } - return FALSE; -} - -static gint gtk_clist_button_press (GtkWidget *widget, GdkEventButton *event) { @@ -6196,6 +6165,7 @@ hadjustment_value_changed (GtkAdjustment *adjustment, gpointer data) { GtkCList *clist; + GtkContainer *container; GdkRectangle area; gint i; gint y = 0; @@ -6207,6 +6177,7 @@ hadjustment_value_changed (GtkAdjustment *adjustment, g_return_if_fail (GTK_IS_CLIST (data)); clist = GTK_CLIST (data); + container = GTK_CONTAINER (data); if (!GTK_WIDGET_DRAWABLE (clist) || adjustment != clist->hadjustment) return; @@ -6250,7 +6221,7 @@ hadjustment_value_changed (GtkAdjustment *adjustment, } if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && - !GTK_CLIST_CHILD_HAS_FOCUS(clist) && GTK_CLIST_ADD_MODE(clist)) + !container->focus_child && GTK_CLIST_ADD_MODE(clist)) { y = ROW_TOP_YPIXEL (clist, clist->focus_row); @@ -6285,7 +6256,7 @@ hadjustment_value_changed (GtkAdjustment *adjustment, } if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && - !GTK_CLIST_CHILD_HAS_FOCUS(clist) && GTK_CLIST_ADD_MODE(clist)) + !container->focus_child && GTK_CLIST_ADD_MODE(clist)) { y = ROW_TOP_YPIXEL (clist, clist->focus_row); @@ -6313,7 +6284,7 @@ hadjustment_value_changed (GtkAdjustment *adjustment, check_exposures (clist); if (GTK_WIDGET_CAN_FOCUS(clist) && GTK_WIDGET_HAS_FOCUS(clist) && - !GTK_CLIST_CHILD_HAS_FOCUS(clist)) + !container->focus_child) { if (GTK_CLIST_ADD_MODE(clist)) { @@ -6503,109 +6474,115 @@ row_delete (GtkCList *clist, } /* FOCUS FUNCTIONS + * gtk_clist_focus_content_area * gtk_clist_focus * gtk_clist_draw_focus * gtk_clist_focus_in * gtk_clist_focus_out - * gtk_clist_set_focus_child * title_focus */ -static gint +static void +gtk_clist_focus_content_area (GtkCList *clist) +{ + if (clist->focus_row < 0) + { + clist->focus_row = 0; + + if ((clist->selection_mode == GTK_SELECTION_BROWSE || + clist->selection_mode == GTK_SELECTION_EXTENDED) && + !clist->selection) + gtk_signal_emit (GTK_OBJECT (clist), + clist_signals[SELECT_ROW], + clist->focus_row, -1, NULL); + } + gtk_widget_grab_focus (GTK_WIDGET (clist)); +} + +static gboolean gtk_clist_focus (GtkContainer *container, GtkDirectionType direction) { - GtkCList *clist; - GtkWidget *focus_child; - gint old_row; - - g_return_val_if_fail (container != NULL, FALSE); - g_return_val_if_fail (GTK_IS_CLIST (container), FALSE); + GtkCList *clist = GTK_CLIST (container); + GtkWidget *focus_child = container->focus_child; + gboolean is_current_focus; if (!GTK_WIDGET_IS_SENSITIVE (container)) return FALSE; - - clist = GTK_CLIST (container); - focus_child = container->focus_child; - old_row = clist->focus_row; + is_current_focus = gtk_widget_is_focus (GTK_WIDGET (clist)); + + if (focus_child && + GTK_IS_CONTAINER (focus_child) && + GTK_WIDGET_DRAWABLE (focus_child) && + GTK_WIDGET_IS_SENSITIVE (focus_child) && + gtk_container_focus (GTK_CONTAINER (focus_child), direction)) + return TRUE; + switch (direction) { case GTK_DIR_LEFT: case GTK_DIR_RIGHT: - if (GTK_CLIST_CHILD_HAS_FOCUS(clist)) + if (focus_child) { - if (title_focus (clist, direction)) + if (title_focus_move (clist, direction)) return TRUE; - gtk_container_set_focus_child (container, NULL); - return FALSE; - } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; + } + else if (!is_current_focus) + { + gtk_clist_focus_content_area (clist); + return TRUE; + } + break; case GTK_DIR_DOWN: case GTK_DIR_TAB_FORWARD: - if (GTK_CLIST_CHILD_HAS_FOCUS(clist)) + if (!focus_child && !is_current_focus) { - gboolean tf = FALSE; - - if (((focus_child && direction == GTK_DIR_DOWN) || - !(tf = title_focus (clist, GTK_DIR_TAB_FORWARD))) - && clist->rows) - { - if (clist->focus_row < 0) - { - clist->focus_row = 0; - - if ((clist->selection_mode == GTK_SELECTION_BROWSE || - clist->selection_mode == GTK_SELECTION_EXTENDED) && - !clist->selection) - gtk_signal_emit (GTK_OBJECT (clist), - clist_signals[SELECT_ROW], - clist->focus_row, -1, NULL); - } - gtk_widget_grab_focus (GTK_WIDGET (container)); - return TRUE; - } - - if (tf) + if (title_focus_in (clist, direction)) return TRUE; } - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); + if (!is_current_focus && clist->rows) + { + gtk_clist_focus_content_area (clist); + return TRUE; + } break; case GTK_DIR_UP: case GTK_DIR_TAB_BACKWARD: - if (!focus_child && - GTK_CLIST_CHILD_HAS_FOCUS(clist) && clist->rows) + if (!focus_child && is_current_focus) { - if (clist->focus_row < 0) - { - clist->focus_row = 0; - if ((clist->selection_mode == GTK_SELECTION_BROWSE || - clist->selection_mode == GTK_SELECTION_EXTENDED) && - !clist->selection) - gtk_signal_emit (GTK_OBJECT (clist), - clist_signals[SELECT_ROW], - clist->focus_row, -1, NULL); - } - gtk_widget_grab_focus (GTK_WIDGET (container)); + if (title_focus_in (clist, direction)) + return TRUE; + } + + if (!is_current_focus && !focus_child && clist->rows) + { + gtk_clist_focus_content_area (clist); return TRUE; } - - GTK_CLIST_SET_FLAG (clist, CLIST_CHILD_HAS_FOCUS); - - if (title_focus (clist, direction)) - return TRUE; - break; default: break; } - gtk_container_set_focus_child (container, NULL); return FALSE; } static void +gtk_clist_set_focus_child (GtkContainer *container, + GtkWidget *child) +{ + GtkCList *clist = GTK_CLIST (container); + gint i; + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button == child) + clist->focus_header_column = i; + + parent_class->set_focus_child (container, child); +} + +static void gtk_clist_draw_focus (GtkWidget *widget) { GtkCList *clist; @@ -6635,7 +6612,6 @@ gtk_clist_focus_in (GtkWidget *widget, g_return_val_if_fail (event != NULL, FALSE); GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS); - GTK_CLIST_UNSET_FLAG (widget, CLIST_CHILD_HAS_FOCUS); clist = GTK_CLIST (widget); @@ -6668,7 +6644,6 @@ gtk_clist_focus_out (GtkWidget *widget, g_return_val_if_fail (event != NULL, FALSE); GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS); - GTK_CLIST_SET_FLAG (widget, CLIST_CHILD_HAS_FOCUS); gtk_widget_draw_focus (widget); @@ -6679,123 +6654,154 @@ gtk_clist_focus_out (GtkWidget *widget, return FALSE; } -static void -gtk_clist_set_focus_child (GtkContainer *container, - GtkWidget *child) +static gboolean +focus_column (GtkCList *clist, gint column, gint dir) { - g_return_if_fail (container != NULL); - g_return_if_fail (GTK_IS_CLIST (container)); + GtkWidget *child = clist->column[column].button; + + if (GTK_IS_CONTAINER (child) && + gtk_container_focus (GTK_CONTAINER (child), dir)) + { + return TRUE; + } + else if (GTK_WIDGET_CAN_FOCUS (child)) + { + gtk_widget_grab_focus (child); + return TRUE; + } - if (child) + return FALSE; +} + +/* Focus moved onto the headers. Focus first focusable and visible child. + * (FIXME: focus the last focused child if visible) + */ +static gboolean +title_focus_in (GtkCList *clist, gint dir) +{ + gint i; + gint left, right; + + /* Check last focused column */ + if (clist->focus_header_column != -1) + { + i = clist->focus_header_column; + + left = COLUMN_LEFT_XPIXEL (clist, i); + right = left + clist->column[i].area.width; + + if (left >= 0 && right <= clist->clist_window_width) + { + if (focus_column (clist, i, dir)) + return TRUE; + } + } + + /* Check fully visible columns */ + for (i = 0 ; i < clist->columns ; i++) { - g_return_if_fail (GTK_IS_WIDGET (child)); - GTK_CLIST_SET_FLAG (container, CLIST_CHILD_HAS_FOCUS); + left = COLUMN_LEFT_XPIXEL (clist, i); + right = left + clist->column[i].area.width; + + if (left >= 0 && right <= clist->clist_window_width) + { + if (focus_column (clist, i, dir)) + return TRUE; + } } - parent_class->set_focus_child (container, child); + /* Check partially visible columns */ + for (i = 0 ; i < clist->columns ; i++) + { + left = COLUMN_LEFT_XPIXEL (clist, i); + right = left + clist->column[i].area.width; + + if ((left < 0 && right > 0) || + (left < clist->clist_window_width && right > clist->clist_window_width)) + { + if (focus_column (clist, i, dir)) + return TRUE; + } + } + + return FALSE; } +/* Move the focus right or left within the title buttons, scrolling + * as necessary to keep the focused child visible. + */ static gboolean -title_focus (GtkCList *clist, - gint dir) +title_focus_move (GtkCList *clist, + gint dir) { GtkWidget *focus_child; gboolean return_val = FALSE; - gint last_column; - gint d = 1; - gint i = 0; + gint d = 0; + gint i = -1; gint j; if (!GTK_CLIST_SHOW_TITLES(clist)) return FALSE; focus_child = GTK_CONTAINER (clist)->focus_child; + g_assert (focus_child); - for (last_column = clist->columns - 1; - last_column >= 0 && !clist->column[last_column].visible; last_column--) - ; - + /* Movement direction within headers + */ switch (dir) { - case GTK_DIR_TAB_BACKWARD: - case GTK_DIR_UP: - if (!focus_child || !GTK_CLIST_CHILD_HAS_FOCUS(clist)) - { - if (dir == GTK_DIR_UP) - i = COLUMN_FROM_XPIXEL (clist, 0); - else - i = last_column; - focus_child = clist->column[i].button; - dir = GTK_DIR_TAB_FORWARD; - } - else - d = -1; + case GTK_DIR_RIGHT: + d = 1; break; case GTK_DIR_LEFT: d = -1; - if (!focus_child) - { - i = last_column; - focus_child = clist->column[i].button; - } break; - case GTK_DIR_RIGHT: - if (!focus_child) + } + + for (i = 0; i < clist->columns; i++) + if (clist->column[i].button == focus_child) + break; + + g_assert (i != -1); /* Have a starting column */ + + j = i + d; + while (!return_val && j >= 0 && j < clist->columns) + { + if (clist->column[j].button && + GTK_WIDGET_VISIBLE (clist->column[j].button)) { - i = 0; - focus_child = clist->column[i].button; + if (focus_column (clist, j, dir)) + { + return_val = TRUE; + break; + } } - break; + j += d; } - if (focus_child) - while (i < clist->columns) - { - if (clist->column[i].button == focus_child) - { - if (clist->column[i].button && - GTK_WIDGET_VISIBLE (clist->column[i].button) && - GTK_IS_CONTAINER (clist->column[i].button) && - !GTK_WIDGET_HAS_FOCUS(clist->column[i].button)) - if (gtk_container_focus - (GTK_CONTAINER (clist->column[i].button), dir)) + /* If we didn't find it, wrap around and keep looking + */ + if (!return_val) + { + j = d > 0 ? 0 : clist->columns - 1; + + while (!return_val && j != i) + { + if (clist->column[j].button && + GTK_WIDGET_VISIBLE (clist->column[j].button)) + { + if (focus_column (clist, j, dir)) { return_val = TRUE; - i -= d; + break; } - if (!return_val && dir == GTK_DIR_UP) - return FALSE; - i += d; - break; - } - i++; - } - - j = i; + } + j += d; + } + } - if (!return_val) - while (j >= 0 && j < clist->columns) - { - if (clist->column[j].button && - GTK_WIDGET_VISIBLE (clist->column[j].button)) - { - if (GTK_IS_CONTAINER (clist->column[j].button) && - gtk_container_focus - (GTK_CONTAINER (clist->column[j].button), dir)) - { - return_val = TRUE; - break; - } - else if (GTK_WIDGET_CAN_FOCUS (clist->column[j].button)) - { - gtk_widget_grab_focus (clist->column[j].button); - return_val = TRUE; - break; - } - } - j += d; - } - + /* Scroll horizontally so focused column is visible + */ if (return_val) { if (COLUMN_LEFT_XPIXEL (clist, j) < CELL_SPACING + COLUMN_INSET) @@ -6803,13 +6809,20 @@ title_focus (GtkCList *clist, else if (COLUMN_LEFT_XPIXEL(clist, j) + clist->column[j].area.width > clist->clist_window_width) { + gint last_column; + + for (last_column = clist->columns - 1; + last_column >= 0 && !clist->column[last_column].visible; last_column--); + if (j == last_column) gtk_clist_moveto (clist, -1, j, 0, 0); else gtk_clist_moveto (clist, -1, j, 0, 1); } } - return return_val; + return TRUE; /* Even if we didn't find a new one, we can keep the + * focus in the same place. + */ } /* PRIVATE SCROLLING FUNCTIONS diff --git a/gtk/gtkclist.h b/gtk/gtkclist.h index 7bd437c404..8de30f6927 100644 --- a/gtk/gtkclist.h +++ b/gtk/gtkclist.h @@ -46,7 +46,7 @@ enum { GTK_CLIST_IN_DRAG = 1 << 0, GTK_CLIST_ROW_HEIGHT_SET = 1 << 1, GTK_CLIST_SHOW_TITLES = 1 << 2, - GTK_CLIST_CHILD_HAS_FOCUS = 1 << 3, + /* Unused */ GTK_CLIST_ADD_MODE = 1 << 4, GTK_CLIST_AUTO_SORT = 1 << 5, GTK_CLIST_AUTO_RESIZE_BLOCKED = 1 << 6, @@ -97,7 +97,6 @@ typedef enum #define GTK_CLIST_IN_DRAG(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_IN_DRAG) #define GTK_CLIST_ROW_HEIGHT_SET(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_ROW_HEIGHT_SET) #define GTK_CLIST_SHOW_TITLES(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_SHOW_TITLES) -#define GTK_CLIST_CHILD_HAS_FOCUS(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_CHILD_HAS_FOCUS) #define GTK_CLIST_ADD_MODE(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_ADD_MODE) #define GTK_CLIST_AUTO_SORT(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_AUTO_SORT) #define GTK_CLIST_AUTO_RESIZE_BLOCKED(clist) (GTK_CLIST_FLAGS (clist) & GTK_CLIST_AUTO_RESIZE_BLOCKED) @@ -225,6 +224,8 @@ struct _GtkCList /* focus handling */ gint focus_row; + + gint focus_header_column; /* dragging the selection */ gint anchor; diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 053a6a893a..d3ee4fbffa 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -24,13 +24,15 @@ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. */ +#include <stdarg.h> #include <string.h> +#include <stdlib.h> + #include "gtkcontainer.h" #include "gtkprivate.h" #include "gtksignal.h" #include "gtkmain.h" -#include <stdarg.h> - +#include "gtkwindow.h" enum { ADD, @@ -59,41 +61,42 @@ struct _GtkChildArgInfo guint seq_id; }; -static void gtk_container_base_class_init (GtkContainerClass *klass); -static void gtk_container_class_init (GtkContainerClass *klass); -static void gtk_container_init (GtkContainer *container); -static void gtk_container_destroy (GtkObject *object); -static void gtk_container_get_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_container_set_arg (GtkObject *object, - GtkArg *arg, - guint arg_id); -static void gtk_container_add_unimplemented (GtkContainer *container, - GtkWidget *widget); -static void gtk_container_remove_unimplemented (GtkContainer *container, - GtkWidget *widget); -static void gtk_container_real_check_resize (GtkContainer *container); -static gint gtk_container_real_focus (GtkContainer *container, - GtkDirectionType direction); -static void gtk_container_real_set_focus_child (GtkContainer *container, - GtkWidget *widget); -static gint gtk_container_focus_tab (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static gint gtk_container_focus_up_down (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static gint gtk_container_focus_left_right (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static gint gtk_container_focus_move (GtkContainer *container, - GList *children, - GtkDirectionType direction); -static void gtk_container_children_callback (GtkWidget *widget, - gpointer client_data); -static void gtk_container_show_all (GtkWidget *widget); -static void gtk_container_hide_all (GtkWidget *widget); +static void gtk_container_base_class_init (GtkContainerClass *klass); +static void gtk_container_class_init (GtkContainerClass *klass); +static void gtk_container_init (GtkContainer *container); +static void gtk_container_destroy (GtkObject *object); +static void gtk_container_get_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_container_set_arg (GtkObject *object, + GtkArg *arg, + guint arg_id); +static void gtk_container_add_unimplemented (GtkContainer *container, + GtkWidget *widget); +static void gtk_container_remove_unimplemented (GtkContainer *container, + GtkWidget *widget); +static void gtk_container_real_check_resize (GtkContainer *container); +static gboolean gtk_container_real_focus (GtkContainer *container, + GtkDirectionType direction); +static void gtk_container_real_set_focus_child (GtkContainer *container, + GtkWidget *widget); +static gboolean gtk_container_focus_tab (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static gboolean gtk_container_focus_up_down (GtkContainer *container, + GList **children, + GtkDirectionType direction); +static gboolean gtk_container_focus_left_right (GtkContainer *container, + GList **children, + GtkDirectionType direction); +static gboolean gtk_container_focus_move (GtkContainer *container, + GList *children, + GtkDirectionType direction); +static void gtk_container_children_callback (GtkWidget *widget, + gpointer client_data); +static void gtk_container_show_all (GtkWidget *widget); +static void gtk_container_hide_all (GtkWidget *widget); + static gchar* gtk_container_child_default_composite_name (GtkContainer *container, GtkWidget *child); @@ -1182,7 +1185,7 @@ gtk_container_foreach_full (GtkContainer *container, notify (callback_data); } -gint +gboolean gtk_container_focus (GtkContainer *container, GtkDirectionType direction) { @@ -1342,7 +1345,7 @@ gtk_container_real_set_focus_child (GtkContainer *container, } } -static gint +static gboolean gtk_container_real_focus (GtkContainer *container, GtkDirectionType direction) { @@ -1364,8 +1367,11 @@ gtk_container_real_focus (GtkContainer *container, if (GTK_WIDGET_CAN_FOCUS (container)) { - gtk_widget_grab_focus (GTK_WIDGET (container)); - return_val = TRUE; + if (!GTK_WIDGET_HAS_FOCUS (container)) + { + gtk_widget_grab_focus (GTK_WIDGET (container)); + return_val = TRUE; + } } else { @@ -1407,11 +1413,11 @@ gtk_container_real_focus (GtkContainer *container, break; case GTK_DIR_UP: case GTK_DIR_DOWN: - return_val = gtk_container_focus_up_down (container, children, direction); + return_val = gtk_container_focus_up_down (container, &children, direction); break; case GTK_DIR_LEFT: case GTK_DIR_RIGHT: - return_val = gtk_container_focus_left_right (container, children, direction); + return_val = gtk_container_focus_left_right (container, &children, direction); break; } @@ -1422,7 +1428,7 @@ gtk_container_real_focus (GtkContainer *container, return return_val; } -static gint +static gboolean gtk_container_focus_tab (GtkContainer *container, GList *children, GtkDirectionType direction) @@ -1493,227 +1499,285 @@ gtk_container_focus_tab (GtkContainer *container, return gtk_container_focus_move (container, children, direction); } -static gint -gtk_container_focus_up_down (GtkContainer *container, - GList *children, - GtkDirectionType direction) +static gboolean +old_focus_coords (GtkContainer *container, GdkRectangle *old_focus_rect) { - GtkWidget *child; - GtkWidget *child2; - GList *tmp_list; - gint dist1, dist2; - gint focus_x; - gint focus_width; - guint length; - guint i, j; - - /* return failure if there isn't a focus child */ - if (container->focus_child) + GtkWidget *widget = GTK_WIDGET (container); + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + + if (toplevel && + GTK_IS_WINDOW (toplevel) && GTK_WINDOW (toplevel)->focus_widget && + GTK_WIDGET_REALIZED (container) && + GTK_WIDGET_REALIZED (GTK_WINDOW (toplevel)->focus_widget)) { - focus_width = container->focus_child->allocation.width / 2; - focus_x = container->focus_child->allocation.x + focus_width; + GtkWidget *old_focus = GTK_WINDOW (toplevel)->focus_widget; + GdkWindow *old_parent_window = old_focus->parent ? old_focus->parent->window : old_focus->window; + GdkWindow *new_parent_window = widget->window; + GdkWindow *toplevel_window = toplevel->window; + + *old_focus_rect = old_focus->allocation; + + /* Translate coordinates to the toplevel */ + + while (old_parent_window != toplevel_window) + { + gint dx, dy; + + gdk_window_get_position (old_parent_window, &dx, &dy); + + old_focus_rect->x += dx; + old_focus_rect->y += dy; + + old_parent_window = gdk_window_get_parent (old_parent_window); + } + + /* Translate coordinates back to the new container */ + + while (new_parent_window != toplevel_window) + { + gint dx, dy; + + gdk_window_get_position (new_parent_window, &dx, &dy); + + old_focus_rect->x -= dx; + old_focus_rect->y -= dy; + + new_parent_window = gdk_window_get_parent (new_parent_window); + } + + return TRUE; } - else + + return FALSE; +} + +typedef struct _CompareInfo CompareInfo; + +struct _CompareInfo +{ + gint x; + gint y; +}; + +static gint +up_down_compare (gconstpointer a, + gconstpointer b, + gpointer data) +{ + const GtkWidget *child1 = a; + const GtkWidget *child2 = b; + CompareInfo *compare = data; + + gint y1 = child1->allocation.y + child1->allocation.height / 2; + gint y2 = child2->allocation.y + child2->allocation.height / 2; + + if (y1 == y2) { - focus_width = GTK_WIDGET (container)->allocation.width; - if (GTK_WIDGET_NO_WINDOW (container)) - focus_x = GTK_WIDGET (container)->allocation.x; + gint x1 = abs (child1->allocation.x + child1->allocation.width / 2 - compare->x); + gint x2 = abs (child2->allocation.x + child2->allocation.width / 2 - compare->x); + + if (compare->y < y1) + return (x1 < x2) ? -1 : ((x1 == x2) ? 0 : 1); else - focus_x = 0; + return (x1 < x2) ? 1 : ((x1 == x2) ? 0 : -1); } + else + return (y1 < y2) ? -1 : 1; +} - length = g_list_length (children); +static gboolean +gtk_container_focus_up_down (GtkContainer *container, + GList **children, + GtkDirectionType direction) +{ + CompareInfo compare; + GList *tmp_list; - /* sort the children in the y direction */ - for (i = 1; i < length; i++) + if (container->focus_child) { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; + gint compare_x1; + gint compare_x2; + gint compare_y; + + /* Delete widgets from list that don't match minimum criteria */ - while (j > 0) + compare_x1 = container->focus_child->allocation.x; + compare_x2 = container->focus_child->allocation.x + container->focus_child->allocation.width; + + if (direction == GTK_DIR_UP) + compare_y = container->focus_child->allocation.y; + else + compare_y = container->focus_child->allocation.y + container->focus_child->allocation.height; + + tmp_list = *children; + while (tmp_list) { - child2 = tmp_list->prev->data; - if (child->allocation.y < child2->allocation.y) + GtkWidget *child = tmp_list->data; + GList *next = tmp_list->next; + gint child_x1, child_x2; + + if (child != container->focus_child) { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; + child_x1 = child->allocation.x; + child_x2 = child->allocation.x + child->allocation.width; + + if ((child_x2 <= compare_x1 || child_x1 >= compare_x2) /* No horizontal overlap */ || + (direction == GTK_DIR_DOWN && child->allocation.y + child->allocation.height < compare_y) || /* Not below */ + (direction == GTK_DIR_UP && child->allocation.y > compare_y)) /* Not above */ + { + *children = g_list_delete_link (*children, tmp_list); + } } - else - break; + + tmp_list = next; } - tmp_list->data = child; + compare.x = (compare_x1 + compare_x2) / 2; + compare.y = container->focus_child->allocation.y + container->focus_child->allocation.height / 2; } - - /* sort the children in distance in the x direction - * in distance from the current focus child while maintaining the - * sort in the y direction - */ - for (i = 1; i < length; i++) + else { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; - dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; + /* No old focus widget, need to figure out starting x,y some other way + */ + GtkWidget *widget = GTK_WIDGET (container); + GdkRectangle old_focus_rect; - while (j > 0) + if (old_focus_coords (container, &old_focus_rect)) { - child2 = tmp_list->prev->data; - dist2 = (child2->allocation.x + child2->allocation.width / 2) - focus_x; - - if ((dist1 < dist2) && - (child->allocation.y >= child2->allocation.y)) - { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; - } + compare.x = old_focus_rect.x + old_focus_rect.width / 2; + } + else + { + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.x = widget->allocation.x + widget->allocation.width / 2; else - break; + compare.x = widget->allocation.width / 2; } - - tmp_list->data = child; + + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.y = (direction == GTK_DIR_DOWN) ? widget->allocation.y : widget->allocation.y + widget->allocation.height; + else + compare.y = (direction == GTK_DIR_DOWN) ? 0 : + widget->allocation.height; } - /* go and invalidate any widget which is too - * far from the focus widget. - */ - if (!container->focus_child && - (direction == GTK_DIR_UP)) - focus_x += focus_width; + *children = g_list_sort_with_data (*children, up_down_compare, &compare); - tmp_list = children; - while (tmp_list) - { - child = tmp_list->data; + if (direction == GTK_DIR_UP) + *children = g_list_reverse (*children); - dist1 = (child->allocation.x + child->allocation.width / 2) - focus_x; - if (((direction == GTK_DIR_DOWN) && (dist1 < 0)) || - ((direction == GTK_DIR_UP) && (dist1 > 0))) - tmp_list->data = NULL; + return gtk_container_focus_move (container, *children, direction); +} - tmp_list = tmp_list->next; - } +static gint +left_right_compare (gconstpointer a, + gconstpointer b, + gpointer data) +{ + const GtkWidget *child1 = a; + const GtkWidget *child2 = b; + CompareInfo *compare = data; - if (direction == GTK_DIR_UP) - children = g_list_reverse (children); + gint x1 = child1->allocation.x + child1->allocation.width / 2; + gint x2 = child2->allocation.x + child2->allocation.width / 2; - return gtk_container_focus_move (container, children, direction); + if (x1 == x2) + { + gint y1 = abs (child1->allocation.y + child1->allocation.height / 2 - compare->y); + gint y2 = abs (child2->allocation.y + child2->allocation.height / 2 - compare->y); + + if (compare->x < x1) + return (y1 < y2) ? -1 : ((y1 == y2) ? 0 : 1); + else + return (y1 < y2) ? 1 : ((y1 == y2) ? 0 : -1); + } + else + return (x1 < x2) ? -1 : 1; } -static gint +static gboolean gtk_container_focus_left_right (GtkContainer *container, - GList *children, + GList **children, GtkDirectionType direction) { - GtkWidget *child; - GtkWidget *child2; + CompareInfo compare; GList *tmp_list; - gint dist1, dist2; - gint focus_y; - gint focus_height; - guint length; - guint i, j; - /* return failure if there isn't a focus child */ if (container->focus_child) { - focus_height = container->focus_child->allocation.height / 2; - focus_y = container->focus_child->allocation.y + focus_height; - } - else - { - focus_height = GTK_WIDGET (container)->allocation.height; - if (GTK_WIDGET_NO_WINDOW (container)) - focus_y = GTK_WIDGET (container)->allocation.y; - else - focus_y = 0; - } + gint compare_y1; + gint compare_y2; + gint compare_x; + + /* Delete widgets from list that don't match minimum criteria */ - length = g_list_length (children); + compare_y1 = container->focus_child->allocation.y; + compare_y2 = container->focus_child->allocation.y + container->focus_child->allocation.height; - /* sort the children in the x direction */ - for (i = 1; i < length; i++) - { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; - - while (j > 0) + if (direction == GTK_DIR_LEFT) + compare_x = container->focus_child->allocation.x; + else + compare_x = container->focus_child->allocation.x + container->focus_child->allocation.width; + + tmp_list = *children; + while (tmp_list) { - child2 = tmp_list->prev->data; - if (child->allocation.x < child2->allocation.x) + GtkWidget *child = tmp_list->data; + GList *next = tmp_list->next; + gint child_y1, child_y2; + + if (child != container->focus_child) { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; + child_y1 = child->allocation.y; + child_y2 = child->allocation.y + child->allocation.height; + + if ((child_y2 <= compare_y1 || child_y1 >= compare_y2) /* No vertical overlap */ || + (direction == GTK_DIR_RIGHT && child->allocation.x + child->allocation.width < compare_x) || /* Not to left */ + (direction == GTK_DIR_LEFT && child->allocation.x > compare_x)) /* Not to right */ + { + *children = g_list_delete_link (*children, tmp_list); + } } - else - break; + + tmp_list = next; } - tmp_list->data = child; + compare.y = (compare_y1 + compare_y2) / 2; + compare.x = container->focus_child->allocation.x + container->focus_child->allocation.width / 2; } - - /* sort the children in distance in the y direction - * in distance from the current focus child while maintaining the - * sort in the x direction - */ - for (i = 1; i < length; i++) + else { - j = i; - tmp_list = g_list_nth (children, j); - child = tmp_list->data; - dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; + /* No old focus widget, need to figure out starting x,y some other way + */ + GtkWidget *widget = GTK_WIDGET (container); + GdkRectangle old_focus_rect; - while (j > 0) + if (old_focus_coords (container, &old_focus_rect)) { - child2 = tmp_list->prev->data; - dist2 = (child2->allocation.y + child2->allocation.height / 2) - focus_y; - - if ((dist1 < dist2) && - (child->allocation.x >= child2->allocation.x)) - { - tmp_list->data = tmp_list->prev->data; - tmp_list = tmp_list->prev; - j--; - } + compare.y = old_focus_rect.y + old_focus_rect.height / 2; + } + else + { + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.y = widget->allocation.y + widget->allocation.height / 2; else - break; + compare.y = widget->allocation.height / 2; } - - tmp_list->data = child; + + if (GTK_WIDGET_NO_WINDOW (widget)) + compare.x = (direction == GTK_DIR_RIGHT) ? widget->allocation.x : widget->allocation.x + widget->allocation.width; + else + compare.x = (direction == GTK_DIR_RIGHT) ? 0 : widget->allocation.width; } - /* go and invalidate any widget which is too - * far from the focus widget. - */ - if (!container->focus_child && - (direction == GTK_DIR_LEFT)) - focus_y += focus_height; - - tmp_list = children; - while (tmp_list) - { - child = tmp_list->data; - - dist1 = (child->allocation.y + child->allocation.height / 2) - focus_y; - if (((direction == GTK_DIR_RIGHT) && (dist1 < 0)) || - ((direction == GTK_DIR_LEFT) && (dist1 > 0))) - tmp_list->data = NULL; - - tmp_list = tmp_list->next; - } + *children = g_list_sort_with_data (*children, left_right_compare, &compare); if (direction == GTK_DIR_LEFT) - children = g_list_reverse (children); + *children = g_list_reverse (*children); - return gtk_container_focus_move (container, children, direction); + return gtk_container_focus_move (container, *children, direction); } -static gint +static gboolean gtk_container_focus_move (GtkContainer *container, GList *children, GtkDirectionType direction) @@ -1722,7 +1786,6 @@ gtk_container_focus_move (GtkContainer *container, GtkWidget *child; focus_child = container->focus_child; - gtk_container_set_focus_child (container, NULL); while (children) { @@ -1739,8 +1802,7 @@ gtk_container_focus_move (GtkContainer *container, focus_child = NULL; if (GTK_WIDGET_DRAWABLE (child) && - GTK_IS_CONTAINER (child) && - !GTK_WIDGET_HAS_FOCUS (child)) + GTK_IS_CONTAINER (child)) if (gtk_container_focus (GTK_CONTAINER (child), direction)) return TRUE; } diff --git a/gtk/gtkcontainer.h b/gtk/gtkcontainer.h index 93c29c0428..0da0c11845 100644 --- a/gtk/gtkcontainer.h +++ b/gtk/gtkcontainer.h @@ -83,7 +83,7 @@ struct _GtkContainerClass gboolean include_internals, GtkCallback callback, gpointer callbabck_data); - gint (* focus) (GtkContainer *container, + gboolean (* focus) (GtkContainer *container, GtkDirectionType direction); void (* set_focus_child) (GtkContainer *container, GtkWidget *widget); @@ -119,17 +119,17 @@ void gtk_container_set_resize_mode (GtkContainer *container, void gtk_container_check_resize (GtkContainer *container); -void gtk_container_foreach (GtkContainer *container, - GtkCallback callback, - gpointer callback_data); -void gtk_container_foreach_full (GtkContainer *container, - GtkCallback callback, - GtkCallbackMarshal marshal, - gpointer callback_data, - GtkDestroyNotify notify); -GList* gtk_container_children (GtkContainer *container); -gint gtk_container_focus (GtkContainer *container, - GtkDirectionType direction); +void gtk_container_foreach (GtkContainer *container, + GtkCallback callback, + gpointer callback_data); +void gtk_container_foreach_full (GtkContainer *container, + GtkCallback callback, + GtkCallbackMarshal marshal, + gpointer callback_data, + GtkDestroyNotify notify); +GList* gtk_container_children (GtkContainer *container); +gboolean gtk_container_focus (GtkContainer *container, + GtkDirectionType direction); /* Widget-level methods */ diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c index 73f5a35291..424fd869da 100644 --- a/gtk/gtknotebook.c +++ b/gtk/gtknotebook.c @@ -78,6 +78,33 @@ enum { CHILD_ARG_TAB_PACK }; +#define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data) + +struct _GtkNotebookPage +{ + GtkWidget *child; + GtkWidget *tab_label; + GtkWidget *menu_label; + + guint default_menu : 1; /* If true, we create the menu label ourself */ + guint default_tab : 1; /* If true, we create the tab label ourself */ + guint expand : 1; + guint fill : 1; + guint pack : 1; + + GtkRequisition requisition; + GtkAllocation allocation; +}; + +#ifdef G_DISABLE_CHECKS +#define CHECK_FIND_CHILD(notebook, child) \ + gtk_notebook_find_child(notebook, child, \ + G_GNUC_PRETTY_FUNCTION) +#else +#define CHECK_FIND_CHILD(notebook, child) \ + gtk_notebook_find_child(notebook, child, NULL) +#endif + /*** GtkNotebook Methods ***/ static void gtk_notebook_class_init (GtkNotebookClass *klass); static void gtk_notebook_init (GtkNotebook *notebook); @@ -147,7 +174,8 @@ static void gtk_notebook_forall (GtkContainer *container, /*** GtkNotebook Private Functions ***/ static void gtk_notebook_panel_realize (GtkNotebook *notebook); -static void gtk_notebook_expose_tabs (GtkNotebook *notebook); +static void gtk_notebook_redraw_tabs (GtkNotebook *notebook); +static void gtk_notebook_redraw_arrows (GtkNotebook *notebook); static void gtk_notebook_focus_changed (GtkNotebook *notebook, GtkNotebookPage *old_page); static void gtk_notebook_real_remove (GtkNotebook *notebook, @@ -156,6 +184,9 @@ static void gtk_notebook_update_labels (GtkNotebook *notebook); static gint gtk_notebook_timer (GtkNotebook *notebook); static gint gtk_notebook_page_compare (gconstpointer a, gconstpointer b); +static GList *gtk_notebook_find_child (GtkNotebook *notebook, + GtkWidget *child, + const gchar *function); static gint gtk_notebook_real_page_position (GtkNotebook *notebook, GList *list); static GList * gtk_notebook_search_page (GtkNotebook *notebook, @@ -174,8 +205,7 @@ static void gtk_notebook_draw_arrow (GtkNotebook *notebook, static void gtk_notebook_set_shape (GtkNotebook *notebook); /*** GtkNotebook Size Allocate Functions ***/ -static void gtk_notebook_pages_allocate (GtkNotebook *notebook, - GtkAllocation *allocation); +static void gtk_notebook_pages_allocate (GtkNotebook *notebook); static void gtk_notebook_page_allocate (GtkNotebook *notebook, GtkNotebookPage *page, GtkAllocation *allocation); @@ -194,7 +224,8 @@ static void gtk_notebook_real_switch_page (GtkNotebook *notebook, static void gtk_notebook_switch_page (GtkNotebook *notebook, GtkNotebookPage *page, gint page_num); -static gint gtk_notebook_page_select (GtkNotebook *notebook); +static gint gtk_notebook_page_select (GtkNotebook *notebook, + gboolean move_focus); static void gtk_notebook_switch_focus_tab (GtkNotebook *notebook, GList *new_child); static void gtk_notebook_menu_switch_page (GtkWidget *widget, @@ -315,7 +346,7 @@ gtk_notebook_class_init (GtkNotebookClass *class) static void gtk_notebook_init (GtkNotebook *notebook) { - GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS); + GTK_WIDGET_SET_FLAGS (notebook, GTK_CAN_FOCUS | GTK_RECEIVES_DEFAULT); GTK_WIDGET_UNSET_FLAGS (notebook, GTK_NO_WINDOW); notebook->cur_page = NULL; @@ -340,6 +371,14 @@ gtk_notebook_init (GtkNotebook *notebook) notebook->have_visible_child = FALSE; } +/** + * gtk_notebook_new: + * @void: + * + * Creates a new #GtkNotebook widget with no pages. + + * Return value: the newly created #GtkNotebook + **/ GtkWidget* gtk_notebook_new (void) { @@ -500,7 +539,7 @@ gtk_notebook_map (GtkWidget *widget) gtk_widget_map (notebook->cur_page->child); if (notebook->scrollable) - gtk_notebook_pages_allocate (notebook, &(widget->allocation)); + gtk_notebook_pages_allocate (notebook); else { children = notebook->children; @@ -915,7 +954,7 @@ gtk_notebook_size_allocate (GtkWidget *widget, gtk_widget_size_allocate (page->child, &child_allocation); } - gtk_notebook_pages_allocate (notebook, allocation); + gtk_notebook_pages_allocate (notebook); } gtk_notebook_set_shape (notebook); } @@ -956,7 +995,51 @@ gtk_notebook_expose (GtkWidget *widget, return FALSE; } -static gint +static gboolean +gtk_notebook_arrow_button_press (GtkNotebook *notebook, + GdkEventButton *event) +{ + GtkWidget *widget = GTK_WIDGET (notebook); + + GtkArrowType arrow = event->x <= ARROW_SIZE + ARROW_SPACING / 2 ? GTK_ARROW_LEFT : GTK_ARROW_RIGHT; + + if (!GTK_WIDGET_HAS_FOCUS (widget)) + gtk_widget_grab_focus (widget); + + notebook->button = event->button; + notebook->click_child = arrow; + + if (event->button == 1) + { + if (!notebook->focus_tab || + gtk_notebook_search_page (notebook, notebook->focus_tab, + arrow == GTK_ARROW_LEFT ? STEP_PREV : STEP_NEXT, + TRUE)) + gtk_container_focus (GTK_CONTAINER (notebook), + arrow == GTK_ARROW_LEFT ? GTK_DIR_LEFT : GTK_DIR_RIGHT); + + if (!notebook->timer) + { + notebook->timer = gtk_timeout_add + (NOTEBOOK_INIT_SCROLL_DELAY, + (GtkFunction) gtk_notebook_timer, (gpointer) notebook); + notebook->need_timer = TRUE; + } + } + else if (event->button == 2) + gtk_notebook_page_select (notebook, TRUE); + else if (event->button == 3) + gtk_notebook_switch_focus_tab (notebook, + gtk_notebook_search_page (notebook, + NULL, + arrow == GTK_ARROW_LEFT ? STEP_NEXT : STEP_PREV, + TRUE)); + gtk_notebook_redraw_arrows (notebook); + + return TRUE; +} + +static gboolean gtk_notebook_button_press (GtkWidget *widget, GdkEventButton *event) { @@ -977,66 +1060,7 @@ gtk_notebook_button_press (GtkWidget *widget, if (event->window == notebook->panel) { - if (!GTK_WIDGET_HAS_FOCUS (widget)) - gtk_widget_grab_focus (widget); - - gtk_grab_add (widget); - notebook->button = event->button; - - if (event->x <= ARROW_SIZE + ARROW_SPACING / 2) - { - notebook->click_child = GTK_ARROW_LEFT; - if (event->button == 1) - { - if (!notebook->focus_tab || - gtk_notebook_search_page (notebook, notebook->focus_tab, - STEP_PREV, TRUE)) - gtk_container_focus (GTK_CONTAINER (notebook), GTK_DIR_LEFT); - - if (!notebook->timer) - { - notebook->timer = gtk_timeout_add - (NOTEBOOK_INIT_SCROLL_DELAY, - (GtkFunction) gtk_notebook_timer, (gpointer) notebook); - notebook->need_timer = TRUE; - } - } - else if (event->button == 2) - gtk_notebook_page_select (GTK_NOTEBOOK (widget)); - else if (event->button == 3) - gtk_notebook_switch_focus_tab (notebook, - gtk_notebook_search_page (notebook, - NULL, - STEP_NEXT, - TRUE)); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT); - } - else - { - notebook->click_child = GTK_ARROW_RIGHT; - if (event->button == 1) - { - if (!notebook->focus_tab || - gtk_notebook_search_page (notebook, notebook->focus_tab, - STEP_NEXT, TRUE)) - gtk_container_focus (GTK_CONTAINER (notebook), GTK_DIR_RIGHT); - - if (!notebook->timer) - { - notebook->timer = gtk_timeout_add - (NOTEBOOK_INIT_SCROLL_DELAY, - (GtkFunction) gtk_notebook_timer, (gpointer) notebook); - notebook->need_timer = TRUE; - } - } - else if (event->button == 2) - gtk_notebook_page_select (GTK_NOTEBOOK (widget)); - else if (event->button == 3) - gtk_notebook_switch_focus_tab - (notebook, gtk_notebook_search_page (notebook, NULL, - STEP_PREV, TRUE)); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT); - } + return gtk_notebook_arrow_button_press (notebook, event); } else if (event->window == widget->window) { @@ -1044,7 +1068,7 @@ gtk_notebook_button_press (GtkWidget *widget, { gtk_menu_popup (GTK_MENU (notebook->menu), NULL, NULL, NULL, NULL, 3, event->time); - return FALSE; + return TRUE; } num = 0; @@ -1086,8 +1110,8 @@ gtk_notebook_button_press (GtkWidget *widget, if (!children && !GTK_WIDGET_HAS_FOCUS (widget)) gtk_widget_grab_focus (widget); } - gtk_notebook_set_shape (notebook); - return FALSE; + + return TRUE; } static gint @@ -1115,11 +1139,10 @@ gtk_notebook_button_release (GtkWidget *widget, notebook->timer = 0; notebook->need_timer = FALSE; } - gtk_grab_remove (widget); click_child = notebook->click_child; notebook->click_child = 0; notebook->button = 0; - gtk_notebook_draw_arrow (notebook, click_child); + gtk_notebook_redraw_arrows (notebook); } return FALSE; @@ -1145,19 +1168,11 @@ gtk_notebook_enter_notify (GtkWidget *widget, gdk_window_get_pointer (notebook->panel, &x, &y, NULL); if (x <= ARROW_SIZE + ARROW_SPACING / 2) - { - notebook->in_child = GTK_ARROW_LEFT; - - if (notebook->click_child == 0) - gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT); - } - else - { - notebook->in_child = GTK_ARROW_RIGHT; + notebook->in_child = GTK_ARROW_LEFT; + else + notebook->in_child = GTK_ARROW_RIGHT; - if (notebook->click_child == 0) - gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT); - } + gtk_notebook_redraw_arrows (notebook); } return FALSE; @@ -1175,19 +1190,9 @@ gtk_notebook_leave_notify (GtkWidget *widget, notebook = GTK_NOTEBOOK (widget); - if (event->window == notebook->panel && !notebook->click_child) - { - if (notebook->in_child == GTK_ARROW_LEFT) - { - notebook->in_child = 0; - gtk_notebook_draw_arrow (notebook,GTK_ARROW_LEFT); - } - else - { - notebook->in_child = 0; - gtk_notebook_draw_arrow (notebook,GTK_ARROW_RIGHT); - } - } + if (event->window == notebook->panel) + gtk_notebook_redraw_arrows (notebook); + return FALSE; } @@ -1209,27 +1214,21 @@ gtk_notebook_motion_notify (GtkWidget *widget, if (event->window == notebook->panel) { gint x; + GtkArrowType old_child = notebook->in_child; x = event->x; if (event->is_hint) gdk_window_get_pointer (notebook->panel, &x, NULL, NULL); - if (x <= ARROW_SIZE + ARROW_SPACING / 2 && - notebook->in_child == GTK_ARROW_RIGHT) - { - notebook->in_child = GTK_ARROW_LEFT; - gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT); - } - else if (x > ARROW_SIZE + ARROW_SPACING / 2 && - notebook->in_child == GTK_ARROW_LEFT) - { - notebook->in_child = GTK_ARROW_RIGHT; - gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT); - } - return FALSE; + if (x <= ARROW_SIZE + ARROW_SPACING / 2) + notebook->in_child = GTK_ARROW_LEFT; + else + notebook->in_child = GTK_ARROW_RIGHT; + + if (old_child != notebook->in_child) + gtk_notebook_redraw_arrows (notebook); } + return FALSE; } @@ -1238,7 +1237,6 @@ gtk_notebook_key_press (GtkWidget *widget, GdkEventKey *event) { GtkNotebook *notebook; - GtkDirectionType direction = 0; GList *list; g_return_val_if_fail (widget != NULL, FALSE); @@ -1252,65 +1250,6 @@ gtk_notebook_key_press (GtkWidget *widget, switch (event->keyval) { - case GDK_Up: - switch (notebook->tab_pos) - { - case GTK_POS_BOTTOM: - gtk_notebook_page_select (GTK_NOTEBOOK (widget)); - return TRUE; - case GTK_POS_TOP: - return FALSE; - default: - direction = GTK_DIR_UP; - break; - } - break; - case GDK_Left: - switch (notebook->tab_pos) - { - case GTK_POS_RIGHT: - gtk_notebook_page_select (GTK_NOTEBOOK (widget)); - return TRUE; - case GTK_POS_LEFT: - return FALSE; - default: - direction = GTK_DIR_LEFT; - break; - } - break; - case GDK_Down: - switch (notebook->tab_pos) - { - case GTK_POS_TOP: - gtk_notebook_page_select (GTK_NOTEBOOK (widget)); - return TRUE; - case GTK_POS_BOTTOM: - return FALSE; - default: - direction = GTK_DIR_DOWN; - break; - } - break; - case GDK_Right: - switch (notebook->tab_pos) - { - case GTK_POS_LEFT: - gtk_notebook_page_select (GTK_NOTEBOOK (widget)); - return TRUE; - case GTK_POS_RIGHT: - return FALSE; - default: - direction = GTK_DIR_RIGHT; - break; - } - break; - case GDK_Tab: - case GDK_ISO_Left_Tab: - if (event->state & GDK_SHIFT_MASK) - direction = GTK_DIR_TAB_BACKWARD; - else - direction = GTK_DIR_TAB_FORWARD; - break; case GDK_Home: list = gtk_notebook_search_page (notebook, NULL, STEP_NEXT, TRUE); if (list) @@ -1322,13 +1261,14 @@ gtk_notebook_key_press (GtkWidget *widget, gtk_notebook_switch_focus_tab (notebook, list); return TRUE; case GDK_Return: + gtk_notebook_page_select (GTK_NOTEBOOK (widget), TRUE); + return TRUE; case GDK_space: - gtk_notebook_page_select (GTK_NOTEBOOK (widget)); + gtk_notebook_page_select (GTK_NOTEBOOK (widget), FALSE); return TRUE; - default: - return FALSE; } - return gtk_container_focus (GTK_CONTAINER (widget), direction); + + return FALSE; } static gint @@ -1482,8 +1422,10 @@ gtk_notebook_get_child_arg (GtkContainer *container, notebook = GTK_NOTEBOOK (container); - if (!(list = g_list_find_custom (notebook->children, child, - gtk_notebook_page_compare))) + arg->type = GTK_TYPE_INVALID; + + list = CHECK_FIND_CHILD (notebook, child); + if (!list) { arg->type = GTK_TYPE_INVALID; return; @@ -1572,112 +1514,169 @@ gtk_notebook_remove (GtkContainer *container, } } +static gboolean +focus_tabs_in (GtkNotebook *notebook) +{ + if (notebook->cur_page) + { + gtk_widget_grab_focus (GTK_WIDGET (notebook)); + + gtk_notebook_switch_focus_tab (notebook, + g_list_find (notebook->children, + notebook->cur_page)); + + return TRUE; + } + else + return FALSE; +} + +static gboolean +focus_tabs_move (GtkNotebook *notebook, + GtkDirectionType direction, + gint search_direction) +{ + GList *new_page; + + new_page = gtk_notebook_search_page (notebook, notebook->focus_tab, + search_direction, TRUE); + if (!new_page) + new_page = (search_direction == STEP_NEXT) ? + notebook->children : + g_list_last (notebook->children); + + gtk_notebook_switch_focus_tab (notebook, new_page); + + return TRUE; +} + +static gboolean +focus_child_in (GtkNotebook *notebook, + GtkDirectionType direction) +{ + if (GTK_WIDGET_DRAWABLE (notebook->cur_page->child) && + GTK_WIDGET_IS_SENSITIVE (notebook->cur_page->child)) + { + if (GTK_IS_CONTAINER (notebook->cur_page->child)) + { + if (gtk_container_focus (GTK_CONTAINER (notebook->cur_page->child), direction)) + return TRUE; + } + else if (GTK_WIDGET_CAN_FOCUS (notebook->cur_page->child)) + { + gtk_widget_grab_focus (notebook->cur_page->child); + return TRUE; + } + } + return FALSE; +} + +/* Focus in the notebook can either be on the pages, or on + * the tabs. + */ static gint gtk_notebook_focus (GtkContainer *container, GtkDirectionType direction) { + GtkWidget *old_focus_child; GtkNotebook *notebook; - GtkNotebookPage *page = NULL; - GtkNotebookPage *old_page = NULL; + GtkDirectionType effective_direction; + + /* Remap the directions into the effective direction it would be for a + * GTK_POS_TOP notebook + */ +#define D(rest) GTK_DIR_##rest + + static const GtkDirectionType translate_direction[4][6] = { + /* LEFT */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(LEFT), D(RIGHT), D(UP), D(DOWN) }, + /* RIGHT */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(LEFT), D(RIGHT), D(DOWN), D(UP) }, + /* TOP */ { D(TAB_FORWARD), D(TAB_BACKWARD), D(UP), D(DOWN), D(LEFT), D(RIGHT) }, + /* BOTTOM */ { D(TAB_BACKWARD), D(TAB_FORWARD), D(DOWN), D(UP), D(LEFT), D(RIGHT) }, + }; + +#undef D + + gboolean widget_is_focus; g_return_val_if_fail (container != NULL, FALSE); g_return_val_if_fail (GTK_IS_NOTEBOOK (container), FALSE); notebook = GTK_NOTEBOOK (container); - if (!GTK_WIDGET_DRAWABLE (notebook) || - !GTK_WIDGET_IS_SENSITIVE (container) || - !notebook->children || - !notebook->cur_page) - return FALSE; + widget_is_focus = gtk_widget_is_focus (GTK_WIDGET (container)); + old_focus_child = container->focus_child; - if (!notebook->show_tabs) - { - if (GTK_WIDGET_DRAWABLE (notebook->cur_page->child) && - GTK_WIDGET_IS_SENSITIVE (notebook->cur_page->child)) - { - if (GTK_IS_CONTAINER (notebook->cur_page->child)) - { - if (gtk_container_focus - (GTK_CONTAINER (notebook->cur_page->child), direction)) - return TRUE; - } - else if (GTK_WIDGET_CAN_FOCUS (notebook->cur_page->child)) - { - if (!container->focus_child) - { - gtk_widget_grab_focus (notebook->cur_page->child); - return TRUE; - } - } - } - return FALSE; - } + effective_direction = translate_direction[notebook->tab_pos][direction]; - if (notebook->focus_tab) - old_page = notebook->focus_tab->data; + if (old_focus_child && + GTK_IS_CONTAINER (old_focus_child) && + GTK_WIDGET_DRAWABLE (old_focus_child) && + GTK_WIDGET_IS_SENSITIVE (old_focus_child) && + gtk_container_focus (GTK_CONTAINER (old_focus_child), direction)) + return TRUE; - if (container->focus_child && old_page && - container->focus_child == old_page->child && notebook->child_has_focus) + if (old_focus_child) /* Focus on page child */ { - if (GTK_WIDGET_DRAWABLE (container->focus_child)) + switch (effective_direction) { - if (GTK_IS_CONTAINER (container->focus_child) && - !GTK_WIDGET_HAS_FOCUS (container->focus_child)) - { - if (gtk_container_focus (GTK_CONTAINER (container->focus_child), - direction)) - return TRUE; - } - gtk_widget_grab_focus (GTK_WIDGET(notebook)); - return TRUE; + case GTK_DIR_TAB_BACKWARD: + case GTK_DIR_UP: + /* Focus onto the tabs */ + if (notebook->show_tabs) + return focus_tabs_in (notebook); + else + return FALSE; + case GTK_DIR_DOWN: + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + return FALSE; } - notebook->focus_tab = NULL; - return FALSE; } - - if (!GTK_WIDGET_HAS_FOCUS (container)) - notebook->focus_tab = NULL; - - switch (direction) + else if (widget_is_focus) /* Focus was on tabs */ { - case GTK_DIR_TAB_FORWARD: - case GTK_DIR_RIGHT: - case GTK_DIR_DOWN: - gtk_notebook_switch_focus_tab - (notebook, gtk_notebook_search_page (notebook, notebook->focus_tab, - STEP_NEXT, TRUE)); - break; - case GTK_DIR_TAB_BACKWARD: - case GTK_DIR_LEFT: - case GTK_DIR_UP: - gtk_notebook_switch_focus_tab - (notebook, gtk_notebook_search_page (notebook, notebook->focus_tab, - STEP_PREV, TRUE)); - break; + switch (effective_direction) + { + case GTK_DIR_TAB_BACKWARD: + case GTK_DIR_UP: + return FALSE; + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_DOWN: + return focus_child_in (notebook, direction); + case GTK_DIR_LEFT: + return focus_tabs_move (notebook, direction, STEP_PREV); + case GTK_DIR_RIGHT: + return focus_tabs_move (notebook, direction, STEP_NEXT); + } } - - if (notebook->focus_tab) + else /* Focus was not on widget */ { - if (!GTK_WIDGET_HAS_FOCUS (container)) - gtk_widget_grab_focus (GTK_WIDGET (container)); - - page = notebook->focus_tab->data; - if (GTK_WIDGET_MAPPED (page->tab_label)) - gtk_notebook_focus_changed (notebook, old_page); - else + switch (effective_direction) { - gtk_notebook_pages_allocate (notebook, - &(GTK_WIDGET (notebook)->allocation)); - gtk_notebook_expose_tabs (notebook); + case GTK_DIR_TAB_FORWARD: + case GTK_DIR_DOWN: + if (focus_tabs_in (notebook)) + return TRUE; + if (focus_child_in (notebook, direction)) + return TRUE; + return FALSE; + case GTK_DIR_TAB_BACKWARD: + case GTK_DIR_UP: + if (focus_child_in (notebook, direction)) + return TRUE; + if (focus_tabs_in (notebook)) + return TRUE; + return FALSE; + case GTK_DIR_LEFT: + case GTK_DIR_RIGHT: + return focus_child_in (notebook, direction); } - return TRUE; } - gtk_notebook_focus_changed (notebook, old_page); + g_assert_not_reached (); return FALSE; -} - +} + static void gtk_notebook_set_focus_child (GtkContainer *container, GtkWidget *child) @@ -1754,7 +1753,7 @@ gtk_notebook_child_type (GtkContainer *container) /* Private GtkNotebook Functions: * * gtk_notebook_panel_realize - * gtk_notebook_expose_tabs + * gtk_notebook_redraw_tabs * gtk_notebook_focus_changed * gtk_notebook_real_remove * gtk_notebook_update_labels @@ -1808,11 +1807,11 @@ gtk_notebook_panel_realize (GtkNotebook *notebook) } static void -gtk_notebook_expose_tabs (GtkNotebook *notebook) +gtk_notebook_redraw_tabs (GtkNotebook *notebook) { GtkWidget *widget; GtkNotebookPage *page; - GdkEventExpose event; + GdkRectangle redraw_rect; gint border; widget = GTK_WIDGET (notebook); @@ -1823,42 +1822,49 @@ gtk_notebook_expose_tabs (GtkNotebook *notebook) page = notebook->first_tab->data; - event.type = GDK_EXPOSE; - event.window = widget->window; - event.count = 0; - event.area.x = border; - event.area.y = border; + redraw_rect.x = border; + redraw_rect.y = border; switch (notebook->tab_pos) { case GTK_POS_BOTTOM: - event.area.y = (widget->allocation.height - border - - page->allocation.height - - widget->style->ythickness); + redraw_rect.y = (widget->allocation.height - border - + page->allocation.height - + widget->style->ythickness); if (page != notebook->cur_page) - event.area.y -= widget->style->ythickness; + redraw_rect.y -= widget->style->ythickness; + /* fall through */ case GTK_POS_TOP: - event.area.width = widget->allocation.width - 2 * border; - event.area.height = (page->allocation.height + - widget->style->ythickness); + redraw_rect.width = widget->allocation.width - 2 * border; + redraw_rect.height = (page->allocation.height + + widget->style->ythickness); if (page != notebook->cur_page) - event.area.height += widget->style->ythickness; + redraw_rect.height += widget->style->ythickness; break; case GTK_POS_RIGHT: - event.area.x = (widget->allocation.width - border - - page->allocation.width - - widget->style->xthickness); + redraw_rect.x = (widget->allocation.width - border - + page->allocation.width - + widget->style->xthickness); if (page != notebook->cur_page) - event.area.x -= widget->style->xthickness; + redraw_rect.x -= widget->style->xthickness; + /* fall through */ case GTK_POS_LEFT: - event.area.width = (page->allocation.width + - widget->style->xthickness); - event.area.height = widget->allocation.height - 2 * border; + redraw_rect.width = (page->allocation.width + + widget->style->xthickness); + redraw_rect.height = widget->allocation.height - 2 * border; if (page != notebook->cur_page) - event.area.width += widget->style->xthickness; + redraw_rect.width += widget->style->xthickness; break; - } - gtk_widget_event (widget, (GdkEvent *) &event); + } + + gdk_window_invalidate_rect (widget->window, &redraw_rect, TRUE); +} + +static void +gtk_notebook_redraw_arrows (GtkNotebook *notebook) +{ + if (GTK_WIDGET_MAPPED (notebook) && notebook->panel) + gdk_window_invalidate_rect (notebook->panel, NULL, FALSE); } static void @@ -1944,6 +1950,23 @@ gtk_notebook_page_compare (gconstpointer a, return (((GtkNotebookPage *) a)->child != b); } +static GList * +gtk_notebook_find_child (GtkNotebook *notebook, + GtkWidget *child, + const gchar *function) +{ + GList *list = g_list_find_custom (notebook->children, child, + gtk_notebook_page_compare); + +#ifndef G_DISABLE_CHECKS + if (!list) + g_warning ("child argument to '%s' does not refer to the contents of a notebook page", + function); +#endif + + return list; +} + static void gtk_notebook_real_remove (GtkNotebook *notebook, GList *list) @@ -2565,12 +2588,12 @@ gtk_notebook_set_shape (GtkNotebook *notebook) * gtk_notebook_calc_tabs */ static void -gtk_notebook_pages_allocate (GtkNotebook *notebook, - GtkAllocation *allocation) +gtk_notebook_pages_allocate (GtkNotebook *notebook) { - GtkWidget *widget; - GtkContainer *container; + GtkWidget *widget = GTK_WIDGET (notebook); + GtkContainer *container = GTK_CONTAINER (notebook); GtkNotebookPage *page = NULL; + GtkAllocation *allocation = &widget->allocation; GtkAllocation child_allocation; GList *children = NULL; GList *last_child = NULL; @@ -2587,9 +2610,6 @@ gtk_notebook_pages_allocate (GtkNotebook *notebook, if (!notebook->show_tabs || !notebook->children || !notebook->cur_page) return; - widget = GTK_WIDGET (notebook); - container = GTK_CONTAINER (notebook); - child_allocation.x = container->border_width; child_allocation.y = container->border_width; @@ -2599,13 +2619,16 @@ gtk_notebook_pages_allocate (GtkNotebook *notebook, child_allocation.y = (allocation->height - notebook->cur_page->requisition.height - container->border_width); + /* fall through */ case GTK_POS_TOP: child_allocation.height = notebook->cur_page->requisition.height; break; + case GTK_POS_RIGHT: child_allocation.x = (allocation->width - notebook->cur_page->requisition.width - container->border_width); + /* fall through */ case GTK_POS_LEFT: child_allocation.width = notebook->cur_page->requisition.width; break; @@ -2877,10 +2900,8 @@ gtk_notebook_pages_allocate (GtkNotebook *notebook, { if (children == last_child) { - gtk_notebook_set_shape (notebook); - return; - children = NULL; - break; + /* FIXME double check */ + goto done; } page = children->data; @@ -3007,7 +3028,10 @@ gtk_notebook_pages_allocate (GtkNotebook *notebook, } } } + + done: gtk_notebook_set_shape (notebook); + gtk_notebook_redraw_tabs (notebook); } static void @@ -3305,9 +3329,11 @@ gtk_notebook_switch_page (GtkNotebook *notebook, } static gint -gtk_notebook_page_select (GtkNotebook *notebook) +gtk_notebook_page_select (GtkNotebook *notebook, + gboolean move_focus) { GtkNotebookPage *page; + GtkDirectionType dir = GTK_DIR_DOWN; /* Quiet GCC */ g_return_val_if_fail (notebook != NULL, FALSE); g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), FALSE); @@ -3318,18 +3344,37 @@ gtk_notebook_page_select (GtkNotebook *notebook) page = notebook->focus_tab->data; gtk_notebook_switch_page (notebook, page, -1); - if (GTK_WIDGET_VISIBLE (page->child)) + if (move_focus) { - if (GTK_IS_CONTAINER (page->child)) + switch (notebook->tab_pos) { - if (gtk_container_focus (GTK_CONTAINER (page->child), - GTK_DIR_TAB_FORWARD)) - return TRUE; + case GTK_POS_TOP: + dir = GTK_DIR_DOWN; + break; + case GTK_POS_BOTTOM: + dir = GTK_DIR_UP; + break; + case GTK_POS_LEFT: + dir = GTK_DIR_RIGHT; + break; + case GTK_POS_RIGHT: + dir = GTK_DIR_LEFT; + break; } - else if (GTK_WIDGET_CAN_FOCUS (page->child)) + + if (GTK_WIDGET_VISIBLE (page->child)) { - gtk_widget_grab_focus (page->child); - return TRUE; + if (GTK_IS_CONTAINER (page->child)) + { + if (gtk_container_focus (GTK_CONTAINER (page->child), + dir)) + return TRUE; + } + else if (GTK_WIDGET_CAN_FOCUS (page->child)) + { + gtk_widget_grab_focus (page->child); + return TRUE; + } } } return FALSE; @@ -3353,44 +3398,7 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook, notebook->focus_tab = new_child; if (notebook->scrollable && GTK_WIDGET_DRAWABLE (notebook)) - { - if ((new_child == NULL) != (old_child == NULL)) - { - gdk_window_clear (notebook->panel); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT); - } - else - { - GList *olist; - GList *nlist; - - olist = gtk_notebook_search_page (notebook, old_child, - STEP_PREV, TRUE); - nlist = gtk_notebook_search_page (notebook, new_child, - STEP_PREV, TRUE); - - if ((olist == NULL) != (nlist == NULL)) - { - gdk_window_clear_area (notebook->panel, 0, 0, - ARROW_SIZE, ARROW_SIZE); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_LEFT); - } - - olist = gtk_notebook_search_page (notebook, old_child, - STEP_NEXT, TRUE); - nlist = gtk_notebook_search_page (notebook, new_child, - STEP_NEXT, TRUE); - - if ((olist == NULL) != (nlist == NULL)) - { - gdk_window_clear_area (notebook->panel, - ARROW_SIZE + ARROW_SPACING, 0, - ARROW_SIZE, ARROW_SIZE); - gtk_notebook_draw_arrow (notebook, GTK_ARROW_RIGHT); - } - } - } + gtk_notebook_redraw_arrows (notebook); if (!notebook->show_tabs || !notebook->focus_tab) return; @@ -3402,11 +3410,7 @@ gtk_notebook_switch_focus_tab (GtkNotebook *notebook, if (GTK_WIDGET_MAPPED (page->tab_label)) gtk_notebook_focus_changed (notebook, old_page); else - { - gtk_notebook_pages_allocate (notebook, - &(GTK_WIDGET (notebook)->allocation)); - gtk_notebook_expose_tabs (notebook); - } + gtk_notebook_pages_allocate (notebook); gtk_notebook_set_shape (notebook); } @@ -3510,49 +3514,150 @@ gtk_notebook_menu_detacher (GtkWidget *widget, * gtk_notebook_insert_page_menu * gtk_notebook_remove_page */ +/** + * gtk_notebook_append_page: + * @notebook: a #GtkNotebook + * @child: the #GtkWidget to use as the contents of the page. + * @tab_label: the #GtkWidget to be used as the label for the page, + * or %NULL to use the default label, 'page N'. + * + * Appends a page to @notebook. + **/ void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label) { + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label)); + gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, -1); } +/** + * gtk_notebook_append_page_menu: + * @notebook: a #GtkNotebook + * @child: the #GtkWidget to use as the contents of the page. + * @tab_label: the #GtkWidget to be used as the label for the page, + * or %NULL to use the default label, 'page N'. + * @menu_label: the widget to use as a label for the page-switch + * menu, if that is enabled. If %NULL, and @tab_label + * is a #GtkLabel or %NULL, then the menu label will be + * a newly created label with the same text as @tab_label; + * If @tab_label is not a #GtkLabel, @menu_label must be + * specified if the page-switch menu is to be used. + * + * Appends a page to @notebook, specifying the widget to use as the + * label in the popup menu. + **/ void gtk_notebook_append_page_menu (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, GtkWidget *menu_label) { + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label)); + g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label)); + gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, -1); } +/** + * gtk_notebook_prepend_page: + * @notebook: a #GtkNotebook + * @child: the #GtkWidget to use as the contents of the page. + * @tab_label: the #GtkWidget to be used as the label for the page, + * or %NULL to use the default label, 'page N'. + * + * Prepends a page to @noteobook. + **/ void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label) { + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label)); + gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, 0); } +/** + * gtk_notebook_prepend_page_menu: + * @notebook: a #GtkNotebook + * @child: the #GtkWidget to use as the contents of the page. + * @tab_label: the #GtkWidget to be used as the label for the page, + * or %NULL to use the default label, 'page N'. + * @menu_label: the widget to use as a label for the page-switch + * menu, if that is enabled. If %NULL, and @tab_label + * is a #GtkLabel or %NULL, then the menu label will be + * a newly created label with the same text as @tab_label; + * If @tab_label is not a #GtkLabel, @menu_label must be + * specified if the page-switch menu is to be used. + * + * Prepends a page to @notebook, specifying the widget to use as the + * label in the popup menu. + **/ void gtk_notebook_prepend_page_menu (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, GtkWidget *menu_label) { + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label)); + g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label)); + gtk_notebook_insert_page_menu (notebook, child, tab_label, menu_label, 0); } +/** + * gtk_notebook_insert_page: + * @notebook: a #GtkNotebook + * @child: the #GtkWidget to use as the contents of the page. + * @tab_label: the #GtkWidget to be used as the label for the page, + * or %NULL to use the default label, 'page N'. + * @position: the index (starting at 0) at which to insert the page, + * or -1 to append the page after all other pages. + * + * Insert a page into @notebook at the given position + **/ void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position) { + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label)); + gtk_notebook_insert_page_menu (notebook, child, tab_label, NULL, position); } +/** + * gtk_notebook_insert_page_menu: + * @notebook: a #GtkNotebook + * @child: the #GtkWidget to use as the contents of the page. + * @tab_label: the #GtkWidget to be used as the label for the page, + * or %NULL to use the default label, 'page N'. + * @menu_label: the widget to use as a label for the page-switch + * menu, if that is enabled. If %NULL, and @tab_label + * is a #GtkLabel or %NULL, then the menu label will be + * a newly created label with the same text as @tab_label; + * If @tab_label is not a #GtkLabel, @menu_label must be + * specified if the page-switch menu is to be used. + * @position: the index (starting at 0) at which to insert the page, + * or -1 to append the page after all other pages. + * + * Insert a page into @notebook at the given position, specifying + * the widget to use as the label in the popup menu. + **/ void gtk_notebook_insert_page_menu (GtkNotebook *notebook, GtkWidget *child, @@ -3563,9 +3668,10 @@ gtk_notebook_insert_page_menu (GtkNotebook *notebook, GtkNotebookPage *page; gint nchildren; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); - g_return_if_fail (child != NULL); + g_return_if_fail (GTK_IS_WIDGET (child)); + g_return_if_fail (tab_label == NULL || GTK_IS_WIDGET (tab_label)); + g_return_if_fail (menu_label == NULL || GTK_IS_WIDGET (menu_label)); page = g_new (GtkNotebookPage, 1); page->child = child; @@ -3601,7 +3707,7 @@ gtk_notebook_insert_page_menu (GtkNotebook *notebook, else { gtk_widget_ref (page->menu_label); - gtk_object_sink (GTK_OBJECT(page->menu_label)); + gtk_object_sink (GTK_OBJECT (page->menu_label)); } if (notebook->menu) @@ -3659,6 +3765,16 @@ gtk_notebook_insert_page_menu (GtkNotebook *notebook, } } +/** + * gtk_notebook_remove_page: + * @notebook: a #GtkNotebook. + * @page_num: the index of a notebook page, starting + * from 0. If -1, the last page will + * be removed. + * + * Removes a page from the notebook given its index + * in the notebook. + **/ void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num) @@ -3689,10 +3805,19 @@ gtk_notebook_remove_page (GtkNotebook *notebook, * gtk_notebook_next_page * gtk_notebook_prev_page */ +/** + * gtk_notebook_get_current_page: + * @notebook: a #GtkNotebook + * + * Returns the page number of the current page. + * + * Return value: the index (starting from 0) of the current + * page in the notebook. If the notebook has no pages, then + * -1 will be returned. + **/ gint gtk_notebook_get_current_page (GtkNotebook *notebook) { - g_return_val_if_fail (notebook != NULL, -1); g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1); if (!notebook->cur_page) @@ -3701,13 +3826,22 @@ gtk_notebook_get_current_page (GtkNotebook *notebook) return g_list_index (notebook->children, notebook->cur_page); } +/** + * gtk_notebook_get_nth_page: + * @notebook: a #GtkNotebook + * @page_num: the index of a page in the noteobok + * + * Returns the child widget contained in page number @page_num. + * + * Return value: the child widget, or %NULL if @page_num is + * out of bounds. + **/ GtkWidget* gtk_notebook_get_nth_page (GtkNotebook *notebook, gint page_num) { GtkNotebookPage *page; - g_return_val_if_fail (notebook != NULL, NULL); g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL); page = g_list_nth_data (notebook->children, page_num); @@ -3718,6 +3852,17 @@ gtk_notebook_get_nth_page (GtkNotebook *notebook, return NULL; } +/** + * gtk_notebook_page_num: + * @notebook: a #GtkNotebook + * @child: a #GtkWidget + * + * Finds the index of the page which contains the given child + * widget. + * + * Return value: the index of the page containing @child, or + * -1 if @child is not in the notebook. + **/ gint gtk_notebook_page_num (GtkNotebook *notebook, GtkWidget *child) @@ -3725,16 +3870,14 @@ gtk_notebook_page_num (GtkNotebook *notebook, GList *children; gint num; - g_return_val_if_fail (notebook != NULL, -1); g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), -1); num = 0; children = notebook->children; while (children) { - GtkNotebookPage *page; - - page = children->data; + GtkNotebookPage *page = children->data; + if (page->child == child) return num; @@ -3745,32 +3888,46 @@ gtk_notebook_page_num (GtkNotebook *notebook, return -1; } +/** + * gtk_notebook_set_page: + * @notebook: a #GtkNotebook + * @page_num: index of the page to switch to, starting from 0. + * If negative, or greater than the number of pages + * in the notebook the last page will be used. + * + * Switches to the page number @page_num. + **/ void gtk_notebook_set_page (GtkNotebook *notebook, gint page_num) { GList *list; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); if (page_num >= 0) list = g_list_nth (notebook->children, page_num); else - { - list = g_list_last (notebook->children); - page_num = g_list_length (notebook->children) - 1; - } + list = g_list_last (notebook->children); + + page_num = g_list_index (notebook->children, list); + if (list) gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), page_num); } +/** + * gtk_notebook_next_page: + * @notebook: a #GtkNotebook + * + * Switches to the next page. Nothing happens if the current page is + * the last page. + **/ void gtk_notebook_next_page (GtkNotebook *notebook) { GList *list; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); list = g_list_find (notebook->children, notebook->cur_page); @@ -3784,12 +3941,18 @@ gtk_notebook_next_page (GtkNotebook *notebook) gtk_notebook_switch_page (notebook, GTK_NOTEBOOK_PAGE (list), -1); } +/** + * gtk_notebook_prev_page: + * @notebook: a #GtkNotebook + * + * Switches to the previous page. Nothing happens if the current page + * is the first page. + **/ void gtk_notebook_prev_page (GtkNotebook *notebook) { GList *list; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); list = g_list_find (notebook->children, notebook->cur_page); @@ -3814,6 +3977,15 @@ gtk_notebook_prev_page (GtkNotebook *notebook) * gtk_notebook_set_tab_vborder * gtk_notebook_set_scrollable */ +/** + * gtk_notebook_set_show_border: + * @notebook: a #GtkNotebook + * @show_border: %TRUE if a bevel should be drawn around the notebook. + * + * Sets whether a bevel will be drawn around the notebook pages. + * this is only has an effect when the tabs are not shown. + * See gtk_notebook_set_show_tabs(). + **/ void gtk_notebook_set_show_border (GtkNotebook *notebook, gboolean show_border) @@ -3830,6 +4002,13 @@ gtk_notebook_set_show_border (GtkNotebook *notebook, } } +/** + * gtk_notebook_set_show_tabs: + * @notebook: a #GtkNotebook + * @show_tabs: %TRUE if the tabs should be shown. + * + * Sets whether to show the tabs for the notebook or not. + **/ void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gboolean show_tabs) @@ -3876,11 +4055,18 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook, gtk_widget_queue_resize (GTK_WIDGET (notebook)); } +/** + * gtk_notebook_set_tab_pos: + * @notebook: + * @pos: + * + * Sets the edge at which the tabs for switching pages in the + * notebook are drawn. + **/ void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos) { - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); if (notebook->tab_pos != pos) @@ -3891,11 +4077,17 @@ gtk_notebook_set_tab_pos (GtkNotebook *notebook, } } +/** + * gtk_notebook_set_homogeneous_tabs: + * @notebook: a #GtkNotebook + * @homogeneous: %TRUE if all tabs should be the same size. + * + * Sets whether the tabs must have all the same size or not. + **/ void gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook, gboolean homogeneous) { - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); if (homogeneous == notebook->homogeneous) @@ -3905,11 +4097,21 @@ gtk_notebook_set_homogeneous_tabs (GtkNotebook *notebook, gtk_widget_queue_resize (GTK_WIDGET (notebook)); } +/** + * gtk_notebook_set_tab_border: + * @notebook: a #GtkNotebook + * @tab_border: %TRUE if there should be a border around the + * tab labels. + * + * Sets whether there should be a border around the tab labels + * in a notebook. This is equivalent to calling + * gtk_notebook_set_tab_hborder (@notebook, @tab_border) followed + * by gtk_noteobok_set_tab_vborder (@notebook, @tab_border). + **/ void gtk_notebook_set_tab_border (GtkNotebook *notebook, guint tab_border) { - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); notebook->tab_hborder = tab_border; @@ -3919,11 +4121,18 @@ gtk_notebook_set_tab_border (GtkNotebook *notebook, gtk_widget_queue_resize (GTK_WIDGET (notebook)); } +/** + * gtk_notebook_set_tab_hborder: + * @notebook: a #GtkNotebook + * @tab_vborder: %TRUE if the notebook tabs should have + * a vertical border. + * + * Sets whether the tabs should have a vertical border. + **/ void gtk_notebook_set_tab_hborder (GtkNotebook *notebook, guint tab_hborder) { - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); if (notebook->tab_hborder == tab_hborder) @@ -3935,11 +4144,18 @@ gtk_notebook_set_tab_hborder (GtkNotebook *notebook, gtk_widget_queue_resize (GTK_WIDGET (notebook)); } +/** + * gtk_notebook_set_tab_vborder: + * @notebook: a #GtkNotebook + * @tab_vborder: %TRUE if the notebook tabs should have + * a vertical border. + * + * Sets whether the tabs should have a vertical border. + **/ void gtk_notebook_set_tab_vborder (GtkNotebook *notebook, guint tab_vborder) { - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); if (notebook->tab_vborder == tab_vborder) @@ -3951,11 +4167,19 @@ gtk_notebook_set_tab_vborder (GtkNotebook *notebook, gtk_widget_queue_resize (GTK_WIDGET (notebook)); } +/** + * gtk_notebook_set_scrollable: + * @notebook: a #GtkNotebook + * @scrollable: %TRUE if scroll arrows should be added + * + * Sets whether the tab label area will have arrows for scrolling if + * there are too many tabs to fit in the area. + + **/ void gtk_notebook_set_scrollable (GtkNotebook *notebook, gboolean scrollable) { - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); scrollable = (scrollable != FALSE); @@ -3979,7 +4203,7 @@ gtk_notebook_set_scrollable (GtkNotebook *notebook, } if (GTK_WIDGET_VISIBLE (notebook)) - gtk_widget_queue_resize (GTK_WIDGET(notebook)); + gtk_widget_queue_resize (GTK_WIDGET (notebook)); } } @@ -3988,12 +4212,20 @@ gtk_notebook_set_scrollable (GtkNotebook *notebook, * gtk_notebook_popup_enable * gtk_notebook_popup_disable */ + + +/** + * gtk_notebook_popup_enable: + * @notebook: a #GtkNotebook + * + * Enables the popup menu: if the user clicks with the right mouse button on + * the bookmarks, a menu with all the pages will be popped up. + **/ void gtk_notebook_popup_enable (GtkNotebook *notebook) { GList *list; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); if (notebook->menu) @@ -4011,10 +4243,15 @@ gtk_notebook_popup_enable (GtkNotebook *notebook) gtk_notebook_menu_detacher); } +/** + * gtk_notebook_popup_disable: + * @notebook: a #GtkNotebook + * + * Disables the popup menu. + **/ void gtk_notebook_popup_disable (GtkNotebook *notebook) { - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); if (!notebook->menu) @@ -4036,18 +4273,29 @@ gtk_notebook_popup_disable (GtkNotebook *notebook) * gtk_notebook_set_tab_label_packing * gtk_notebook_query_tab_label_packing */ + +/** + * gtk_notebook_get_tab_label: + * @notebook: a #GtkNotebook + * @child: the page + * + * Returns the tab label widget for the page @child. %NULL is returned + * if @child is not in @notebook or if no tab label has specifically + * been set for @child. + * + * Return value: the tab label + **/ GtkWidget * gtk_notebook_get_tab_label (GtkNotebook *notebook, GtkWidget *child) { GList *list; - g_return_val_if_fail (notebook != NULL, NULL); g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL); g_return_val_if_fail (child != NULL, NULL); - if (!(list = g_list_find_custom (notebook->children, child, - gtk_notebook_page_compare))) + list = CHECK_FIND_CHILD (notebook, child); + if (!list) return NULL; if (GTK_NOTEBOOK_PAGE (list)->default_tab) @@ -4056,6 +4304,16 @@ gtk_notebook_get_tab_label (GtkNotebook *notebook, return GTK_NOTEBOOK_PAGE (list)->tab_label; } +/** + * gtk_notebook_set_tab_label: + * @notebook: a #GtkNotebook + * @child: the page + * @tab_label: the tab label widget to use, or %NULL for default tab + * label. + * + * Changes the tab label for @child. If %NULL is specified + * for @tab_label, then the page will have the label 'page N'. + **/ void gtk_notebook_set_tab_label (GtkNotebook *notebook, GtkWidget *child, @@ -4064,18 +4322,16 @@ gtk_notebook_set_tab_label (GtkNotebook *notebook, GtkNotebookPage *page; GList *list; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); g_return_if_fail (child != NULL); - - if (!(list = g_list_find_custom (notebook->children, child, - gtk_notebook_page_compare))) - return; + + list = CHECK_FIND_CHILD (notebook, child); + if (!list) + return; /* a NULL pointer indicates a default_tab setting, otherwise * we need to set the associated label */ - page = list->data; if (page->tab_label) gtk_widget_unparent (page->tab_label); @@ -4109,6 +4365,15 @@ gtk_notebook_set_tab_label (GtkNotebook *notebook, } } +/** + * gtk_notebook_set_tab_label_text: + * @notebook: a #GtkNotebook + * @child: the page + * @tab_label: the label text + * + * Creates a new label and sets it as the tab label for the page + * containing @child. + **/ void gtk_notebook_set_tab_label_text (GtkNotebook *notebook, GtkWidget *child, @@ -4116,24 +4381,36 @@ gtk_notebook_set_tab_label_text (GtkNotebook *notebook, { GtkWidget *tab_label = NULL; + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + if (tab_text) tab_label = gtk_label_new (tab_text); gtk_notebook_set_tab_label (notebook, child, tab_label); } +/** + * gtk_notebook_get_menu_label: + * @notebook: a #GtkNotebook + * @child: the page + * + * Returns the menu label of the page containing @child. NULL is + * returned if @child is not in @notebook or NULL if it has the + * default menu label. + * + * Return value: the menu label + **/ GtkWidget* gtk_notebook_get_menu_label (GtkNotebook *notebook, GtkWidget *child) { GList *list; - g_return_val_if_fail (notebook != NULL, NULL); g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL); g_return_val_if_fail (child != NULL, NULL); - if (!(list = g_list_find_custom (notebook->children, child, - gtk_notebook_page_compare))) - return NULL; + list = CHECK_FIND_CHILD (notebook, child); + if (!list) + return NULL; if (GTK_NOTEBOOK_PAGE (list)->default_menu) return NULL; @@ -4141,6 +4418,14 @@ gtk_notebook_get_menu_label (GtkNotebook *notebook, return GTK_NOTEBOOK_PAGE (list)->menu_label; } +/** + * gtk_notebook_set_menu_label: + * @notebook: a #GtkNotebook + * @child: the child widget + * @menu_label: the menu label, or NULL for default + * + * Changes the menu label for the page containing @child. + **/ void gtk_notebook_set_menu_label (GtkNotebook *notebook, GtkWidget *child, @@ -4153,19 +4438,17 @@ gtk_notebook_set_menu_label (GtkNotebook *notebook, g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); g_return_if_fail (child != NULL); - if (!(list = g_list_find_custom (notebook->children, child, - gtk_notebook_page_compare))) - return; + list = CHECK_FIND_CHILD (notebook, child); + if (!list) + return; page = list->data; if (page->menu_label) { if (notebook->menu) - { - gtk_container_remove (GTK_CONTAINER (notebook->menu), - page->menu_label->parent); - gtk_widget_queue_resize (notebook->menu); - } + gtk_container_remove (GTK_CONTAINER (notebook->menu), + page->menu_label->parent); + if (!page->default_menu) gtk_widget_unref (page->menu_label); } @@ -4184,6 +4467,14 @@ gtk_notebook_set_menu_label (GtkNotebook *notebook, gtk_notebook_menu_item_create (notebook, list); } +/** + * gtk_notebook_set_menu_label_text: + * @notebook: a #GtkNotebook + * @child: the child widget + * @menu_text: the label text + * + * Creates a new label and sets it as the menu label of @child. + **/ void gtk_notebook_set_menu_label_text (GtkNotebook *notebook, GtkWidget *child, @@ -4191,11 +4482,44 @@ gtk_notebook_set_menu_label_text (GtkNotebook *notebook, { GtkWidget *menu_label = NULL; + g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); + if (menu_text) menu_label = gtk_label_new (menu_text); gtk_notebook_set_menu_label (notebook, child, menu_label); } +/* Helper function called when pages are reordered + */ +static void +gtk_notebook_child_reordered (GtkNotebook *notebook, + GtkNotebookPage *page) +{ + if (notebook->menu) + { + GtkWidget *menu_item; + + menu_item = page->menu_label->parent; + gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label); + gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item); + gtk_notebook_menu_item_create (notebook, g_list_find (notebook->children, page)); + } + + gtk_notebook_update_labels (notebook); +} + +/** + * gtk_notebook_set_tab_label_packing: + * @notebook: a #GtkNotebook + * @child: the child widget + * @expand: whether to expand the bookmark or not + * @fill: whether the bookmark should fill the allocated area or not + * @pack_type: the position of the bookmark + * + * Sets the packing parameters for the tab label of the page + * containing @child. See gtk_box_pack_start() for the exact meaning + * of the parameters. + **/ void gtk_notebook_set_tab_label_packing (GtkNotebook *notebook, GtkWidget *child, @@ -4210,9 +4534,9 @@ gtk_notebook_set_tab_label_packing (GtkNotebook *notebook, g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); g_return_if_fail (child != NULL); - if (!(list = g_list_find_custom (notebook->children, child, - gtk_notebook_page_compare))) - return; + list = CHECK_FIND_CHILD (notebook, child); + if (!list) + return; page = list->data; if (page->pack == pack_type && page->expand == expand && page->fill == fill) @@ -4224,26 +4548,26 @@ gtk_notebook_set_tab_label_packing (GtkNotebook *notebook, if (page->pack != pack_type) { page->pack = pack_type; - if (notebook->menu) - { - GtkWidget *menu_item; - - menu_item = page->menu_label->parent; - gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label); - gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item); - gtk_notebook_menu_item_create (notebook, list); - gtk_widget_queue_resize (notebook->menu); - } - gtk_notebook_update_labels (notebook); + gtk_notebook_child_reordered (notebook, page); } if (!notebook->show_tabs) return; - gtk_notebook_pages_allocate (notebook, &(GTK_WIDGET (notebook)->allocation)); - gtk_notebook_expose_tabs (notebook); + gtk_notebook_pages_allocate (notebook); } +/** + * gtk_notebook_query_tab_label_packing: + * @notebook: a #GtkNotebook + * @child: the page + * @expand: location to store the expand value (or NULL) + * @fill: location to store the fill value (or NULL) + * @pack_type: location to store the pack_type (or NULL) + * + * Query the packing attributes for the tab label of the page + * containing @child. + **/ void gtk_notebook_query_tab_label_packing (GtkNotebook *notebook, GtkWidget *child, @@ -4253,13 +4577,12 @@ gtk_notebook_query_tab_label_packing (GtkNotebook *notebook, { GList *list; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); g_return_if_fail (child != NULL); - if (!(list = g_list_find_custom (notebook->children, child, - gtk_notebook_page_compare))) - return; + list = CHECK_FIND_CHILD (notebook, child); + if (!list) + return; if (expand) *expand = GTK_NOTEBOOK_PAGE (list)->expand; @@ -4269,75 +4592,53 @@ gtk_notebook_query_tab_label_packing (GtkNotebook *notebook, *pack_type = GTK_NOTEBOOK_PAGE (list)->pack; } +/** + * gtk_notebook_reorder_child: + * @notebook: a #GtkNotebook + * @child: the child to move + * @position: the new position + * + * Reorders the page containing @child, so that it appears in position + * @position. Out of bounds @position will be clamped. + **/ void gtk_notebook_reorder_child (GtkNotebook *notebook, GtkWidget *child, gint position) { - GList *list; - GList *work; - GtkNotebookPage *page = NULL; + GList *list, *new_list; + GtkNotebookPage *page; gint old_pos; - g_return_if_fail (notebook != NULL); g_return_if_fail (GTK_IS_NOTEBOOK (notebook)); - g_return_if_fail (child != NULL); g_return_if_fail (GTK_IS_WIDGET (child)); - for (old_pos = 0, list = notebook->children; list; - list = list->next, old_pos++) - { - page = list->data; - if (page->child == child) - break; - } + list = CHECK_FIND_CHILD (notebook, child); + if (!list) + return; - if (!list || old_pos == position) + old_pos = g_list_position (notebook->children, list); + + if (old_pos == position) return; - notebook->children = g_list_remove_link (notebook->children, list); - - if (position <= 0 || !notebook->children) - { - list->next = notebook->children; - if (list->next) - list->next->prev = list; - notebook->children = list; - } - else if (position > 0 && (work = g_list_nth (notebook->children, position))) - { - list->prev = work->prev; - if (list->prev) - list->prev->next = list; - list->next = work; - work->prev = list; - } - else - { - work = g_list_last (notebook->children); - work->next = list; - list->prev = work; - } + page = list->data; + notebook->children = g_list_delete_link (notebook->children, list); - if (notebook->menu) - { - GtkWidget *menu_item; + position = CLAMP (position, 0, g_list_length (notebook->children)); - g_assert(page != NULL); + notebook->children = g_list_insert (notebook->children, page, position); + new_list = g_list_nth (notebook->children, position); - menu_item = page->menu_label->parent; - gtk_container_remove (GTK_CONTAINER (menu_item), page->menu_label); - gtk_container_remove (GTK_CONTAINER (notebook->menu), menu_item); - gtk_notebook_menu_item_create (notebook, list); - gtk_widget_queue_resize (notebook->menu); - } + /* Fix up GList references in GtkNotebook structure */ + if (notebook->first_tab == list) + notebook->first_tab = new_list; + if (notebook->focus_tab == list) + notebook->focus_tab = new_list; - gtk_notebook_update_labels (notebook); + /* Move around the menu items if necesary */ + gtk_notebook_child_reordered (notebook, page); if (notebook->show_tabs) - { - gtk_notebook_pages_allocate (notebook, - &(GTK_WIDGET (notebook)->allocation)); - gtk_notebook_expose_tabs (notebook); - } + gtk_notebook_pages_allocate (notebook); } diff --git a/gtk/gtknotebook.h b/gtk/gtknotebook.h index ffa575c508..8e110b6784 100644 --- a/gtk/gtknotebook.h +++ b/gtk/gtknotebook.h @@ -45,9 +45,6 @@ extern "C" { #define GTK_NOTEBOOK_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GTK_TYPE_NOTEBOOK, GtkNotebookClass)) -#define GTK_NOTEBOOK_PAGE(_glist_) ((GtkNotebookPage *)((GList *)(_glist_))->data) - - typedef struct _GtkNotebook GtkNotebook; typedef struct _GtkNotebookClass GtkNotebookClass; typedef struct _GtkNotebookPage GtkNotebookPage; @@ -58,7 +55,7 @@ struct _GtkNotebook GtkNotebookPage *cur_page; GList *children; - GList *first_tab; + GList *first_tab; /* The first tab visible (for scrolling notebooks) */ GList *focus_tab; GtkWidget *menu; @@ -91,22 +88,6 @@ struct _GtkNotebookClass guint page_num); }; -struct _GtkNotebookPage -{ - GtkWidget *child; - GtkWidget *tab_label; - GtkWidget *menu_label; - - guint default_menu : 1; - guint default_tab : 1; - guint expand : 1; - guint fill : 1; - guint pack : 1; - - GtkRequisition requisition; - GtkAllocation allocation; -}; - /*********************************************************** * Creation, insertion, deletion * ***********************************************************/ @@ -143,15 +124,15 @@ void gtk_notebook_remove_page (GtkNotebook *notebook, * query, set current NoteebookPage * ***********************************************************/ -gint gtk_notebook_get_current_page (GtkNotebook *notebook); -GtkWidget* gtk_notebook_get_nth_page (GtkNotebook *notebook, - gint page_num); -gint gtk_notebook_page_num (GtkNotebook *notebook, - GtkWidget *child); -void gtk_notebook_set_page (GtkNotebook *notebook, - gint page_num); -void gtk_notebook_next_page (GtkNotebook *notebook); -void gtk_notebook_prev_page (GtkNotebook *notebook); +gint gtk_notebook_get_current_page (GtkNotebook *notebook); +GtkWidget* gtk_notebook_get_nth_page (GtkNotebook *notebook, + gint page_num); +gint gtk_notebook_page_num (GtkNotebook *notebook, + GtkWidget *child); +void gtk_notebook_set_page (GtkNotebook *notebook, + gint page_num); +void gtk_notebook_next_page (GtkNotebook *notebook); +void gtk_notebook_prev_page (GtkNotebook *notebook); /*********************************************************** * set Notebook, NotebookTab style * diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c index 1262e94808..01371b801d 100644 --- a/gtk/gtktreeview.c +++ b/gtk/gtktreeview.c @@ -1418,10 +1418,7 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, * I wonder if focussable is a real word... */ if (last_column == NULL) - { - gtk_container_set_focus_child (container, NULL); - return FALSE; - } + return FALSE; /* First thing we want to handle is entering and leaving the headers. */ @@ -1431,7 +1428,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, if (!focus_child) { focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button; - gtk_container_set_focus_child (container, focus_child); gtk_widget_grab_focus (focus_child); goto cleanup; } @@ -1446,7 +1442,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, if (!focus_child) { focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button; - gtk_container_set_focus_child (container, focus_child); gtk_widget_grab_focus (focus_child); goto cleanup; } @@ -1461,7 +1456,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, if (!focus_child) { focus_child = GTK_TREE_VIEW_COLUMN (last_column->data)->button; - gtk_container_set_focus_child (container, focus_child); gtk_widget_grab_focus (focus_child); goto cleanup; } @@ -1476,7 +1470,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, if (!focus_child) { focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button; - gtk_container_set_focus_child (container, focus_child); gtk_widget_grab_focus (focus_child); goto cleanup; } @@ -1491,7 +1484,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, if (!focus_child) { focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button; - gtk_container_set_focus_child (container, focus_child); gtk_widget_grab_focus (focus_child); } else @@ -1504,7 +1496,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, if (!focus_child) { focus_child = GTK_TREE_VIEW_COLUMN (first_column->data)->button; - gtk_container_set_focus_child (container, focus_child); gtk_widget_grab_focus (focus_child); } else @@ -1550,7 +1541,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, GTK_WIDGET_CAN_FOCUS (column->button)) { focus_child = column->button; - gtk_container_set_focus_child (container, column->button); gtk_widget_grab_focus (column->button); break; } @@ -1578,10 +1568,6 @@ gtk_tree_view_header_focus (GtkTreeView *tree_view, focus_child->allocation.x); } } - else - { - gtk_container_set_focus_child (container, NULL); - } return (focus_child != NULL); } @@ -1619,16 +1605,11 @@ gtk_tree_view_focus (GtkContainer *container, case GTK_DIR_TAB_BACKWARD: return (gtk_tree_view_header_focus (tree_view, direction)); case GTK_DIR_UP: - gtk_container_set_focus_child (container, NULL); return FALSE; case GTK_DIR_TAB_FORWARD: case GTK_DIR_RIGHT: case GTK_DIR_DOWN: - if (direction == GTK_DIR_DOWN) - { - gtk_container_set_focus_child (container, NULL); - } - else + if (direction != GTK_DIR_DOWN) { if (gtk_tree_view_header_focus (tree_view, direction)) return TRUE; diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 001b1c8192..315b256d40 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -2857,6 +2857,32 @@ gtk_widget_real_grab_focus (GtkWidget *focus_widget) } /** + * gtk_widget_is_focus: + * @widget: a #GtkWidget + * + * Determines if the widget is the focus widget within its + * toplevel. (This does not mean that the HAS_FOCUS flag is + * necessarily set; HAS_FOCUS will only be set if the + * toplevel widget additionally has the global input focus.) + * + * Return value: %TRUE if the widget is the focus widget. + **/ +gboolean +gtk_widget_is_focus (GtkWidget *widget) +{ + GtkWidget *toplevel; + + g_return_if_fail (GTK_IS_WIDGET (widget)); + + toplevel = gtk_widget_get_toplevel (widget); + + if (GTK_IS_WINDOW (toplevel)) + return widget == GTK_WINDOW (toplevel)->focus_widget; + else + return FALSE; +} + +/** * gtk_widget_grab_default: * @widget: a #GtkWidget * diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 0d86f3fe75..70bfd6b964 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -493,6 +493,7 @@ gboolean gtk_widget_intersect (GtkWidget *widget, GdkRectangle *area, GdkRectangle *intersection); +gboolean gtk_widget_is_focus (GtkWidget *widget); void gtk_widget_grab_focus (GtkWidget *widget); void gtk_widget_grab_default (GtkWidget *widget); diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 7860ef9379..bea9bb646a 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -126,6 +126,8 @@ static gint gtk_window_focus_out_event (GtkWidget *widget, static gint gtk_window_client_event (GtkWidget *widget, GdkEventClient *event); static void gtk_window_check_resize (GtkContainer *container); +static gint gtk_window_focus (GtkContainer *container, + GtkDirectionType direction); static void gtk_window_real_set_focus (GtkWindow *window, GtkWidget *focus); @@ -261,6 +263,7 @@ gtk_window_class_init (GtkWindowClass *klass) widget_class->expose_event = gtk_window_expose; container_class->check_resize = gtk_window_check_resize; + container_class->focus = gtk_window_focus; klass->set_focus = gtk_window_real_set_focus; } @@ -1579,6 +1582,60 @@ gtk_window_check_resize (GtkContainer *container) gtk_window_move_resize (window); } +static gboolean +gtk_window_focus (GtkContainer *container, + GtkDirectionType direction) +{ + GtkBin *bin = GTK_BIN (container); + GtkWindow *window = GTK_WINDOW (container); + GtkWidget *old_focus_child = container->focus_child; + GtkWidget *parent; + + /* We need a special implementation here to deal properly with wrapping + * around in the tab chain without the danger of going into an + * infinite loop. + */ + if (old_focus_child) + { + if (GTK_IS_CONTAINER (old_focus_child) && + GTK_WIDGET_DRAWABLE (old_focus_child) && + GTK_WIDGET_IS_SENSITIVE (old_focus_child) && + gtk_container_focus (GTK_CONTAINER (old_focus_child), direction)) + return TRUE; + } + + if (window->focus_widget) + { + /* Wrapped off the end, clear the focus setting for the toplpevel */ + parent = window->focus_widget->parent; + while (parent) + { + gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL); + parent = GTK_WIDGET (parent)->parent; + } + + gtk_window_set_focus (GTK_WINDOW (container), NULL); + } + + /* Now try to focus the first widget in the window */ + if (GTK_WIDGET_DRAWABLE (bin->child) && + GTK_WIDGET_IS_SENSITIVE (bin->child)) + { + if (GTK_IS_CONTAINER (bin->child)) + { + if (gtk_container_focus (GTK_CONTAINER (bin->child), direction)) + return TRUE; + } + else if (GTK_WIDGET_CAN_FOCUS (bin->child)) + { + gtk_widget_grab_focus (bin->child); + return TRUE; + } + } + + return FALSE; +} + static void gtk_window_real_set_focus (GtkWindow *window, GtkWidget *focus) diff --git a/gtk/testgtk.c b/gtk/testgtk.c index 555ac978b1..e6420d3653 100644 --- a/gtk/testgtk.c +++ b/gtk/testgtk.c @@ -6471,31 +6471,34 @@ GdkBitmap *book_closed_mask; GtkWidget *sample_notebook; static void -page_switch (GtkWidget *widget, GtkNotebookPage *page, gint page_num) +set_page_pixmaps (GtkNotebook *notebook, gint page_num, + GdkPixmap *pixmap, GdkPixmap *mask) { - GtkNotebookPage *oldpage; + GtkWidget *page_widget; GtkWidget *pixwid; - oldpage = GTK_NOTEBOOK (widget)->cur_page; + page_widget = gtk_notebook_get_nth_page (notebook, page_num); + + pixwid = gtk_object_get_data (GTK_OBJECT (page_widget), "tab_pixmap"); + gtk_pixmap_set (GTK_PIXMAP (pixwid), pixmap, mask); + + pixwid = gtk_object_get_data (GTK_OBJECT (page_widget), "menu_pixmap"); + gtk_pixmap_set (GTK_PIXMAP (pixwid), pixmap, mask); +} - if (page == oldpage) +static void +page_switch (GtkWidget *widget, GtkNotebookPage *page, gint page_num) +{ + GtkNotebook *notebook = GTK_NOTEBOOK (widget); + gint old_page_num = gtk_notebook_get_current_page (notebook); + + if (page_num == old_page_num) return; - pixwid = ((GtkBoxChild*) - (GTK_BOX (page->tab_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_open, book_open_mask); - pixwid = ((GtkBoxChild*) - (GTK_BOX (page->menu_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_open, book_open_mask); - - if (oldpage) - { - pixwid = ((GtkBoxChild*) - (GTK_BOX (oldpage->tab_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_closed, book_closed_mask); - pixwid = ((GtkBoxChild*) - (GTK_BOX (oldpage->menu_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_closed, book_closed_mask); - } + + set_page_pixmaps (notebook, page_num, book_open, book_open_mask); + + if (old_page_num != -1) + set_page_pixmaps (notebook, old_page_num, book_closed, book_closed_mask); } static void @@ -6589,19 +6592,25 @@ create_pages (GtkNotebook *notebook, gint start, gint end) label_box = gtk_hbox_new (FALSE, 0); pixwid = gtk_pixmap_new (book_closed, book_closed_mask); + gtk_object_set_data (GTK_OBJECT (child), "tab_pixmap", pixwid); + gtk_box_pack_start (GTK_BOX (label_box), pixwid, FALSE, TRUE, 0); gtk_misc_set_padding (GTK_MISC (pixwid), 3, 1); label = gtk_label_new (buffer); gtk_box_pack_start (GTK_BOX (label_box), label, FALSE, TRUE, 0); gtk_widget_show_all (label_box); + menu_box = gtk_hbox_new (FALSE, 0); pixwid = gtk_pixmap_new (book_closed, book_closed_mask); + gtk_object_set_data (GTK_OBJECT (child), "menu_pixmap", pixwid); + gtk_box_pack_start (GTK_BOX (menu_box), pixwid, FALSE, TRUE, 0); gtk_misc_set_padding (GTK_MISC (pixwid), 3, 1); label = gtk_label_new (buffer); gtk_box_pack_start (GTK_BOX (menu_box), label, FALSE, TRUE, 0); gtk_widget_show_all (menu_box); + gtk_notebook_append_page_menu (notebook, child, label_box, menu_box); } } @@ -6628,6 +6637,7 @@ standard_notebook (GtkButton *button, gint i; gtk_notebook_set_show_tabs (notebook, TRUE); + gtk_notebook_set_show_border (notebook, TRUE); gtk_notebook_set_scrollable (notebook, FALSE); if (g_list_length (notebook->children) == 15) for (i = 0; i < 10; i++) @@ -6641,6 +6651,20 @@ notabs_notebook (GtkButton *button, gint i; gtk_notebook_set_show_tabs (notebook, FALSE); + gtk_notebook_set_show_border (notebook, TRUE); + if (g_list_length (notebook->children) == 15) + for (i = 0; i < 10; i++) + gtk_notebook_remove_page (notebook, 5); +} + +static void +borderless_notebook (GtkButton *button, + GtkNotebook *notebook) +{ + gint i; + + gtk_notebook_set_show_tabs (notebook, FALSE); + gtk_notebook_set_show_border (notebook, FALSE); if (g_list_length (notebook->children) == 15) for (i = 0; i < 10; i++) gtk_notebook_remove_page (notebook, 5); @@ -6651,6 +6675,7 @@ scrollable_notebook (GtkButton *button, GtkNotebook *notebook) { gtk_notebook_set_show_tabs (notebook, TRUE); + gtk_notebook_set_show_border (notebook, TRUE); gtk_notebook_set_scrollable (notebook, TRUE); if (g_list_length (notebook->children) == 5) create_pages (notebook, 6, 15); @@ -6689,7 +6714,8 @@ create_notebook (void) { { "Standard", standard_notebook }, { "No tabs", notabs_notebook }, - { "Scrollable", scrollable_notebook } + { "Borderless", borderless_notebook }, + { "Scrollable", scrollable_notebook }, }; if (!window) @@ -6753,7 +6779,7 @@ create_notebook (void) label = gtk_label_new ("Notebook Style :"); gtk_box_pack_start (GTK_BOX (box2), label, FALSE, TRUE, 0); - omenu = build_option_menu (items, 3, 0, sample_notebook); + omenu = build_option_menu (items, G_N_ELEMENTS (items), 0, sample_notebook); gtk_box_pack_start (GTK_BOX (box2), omenu, FALSE, TRUE, 0); button = gtk_button_new_with_label ("Show all Pages"); diff --git a/tests/testgtk.c b/tests/testgtk.c index 555ac978b1..e6420d3653 100644 --- a/tests/testgtk.c +++ b/tests/testgtk.c @@ -6471,31 +6471,34 @@ GdkBitmap *book_closed_mask; GtkWidget *sample_notebook; static void -page_switch (GtkWidget *widget, GtkNotebookPage *page, gint page_num) +set_page_pixmaps (GtkNotebook *notebook, gint page_num, + GdkPixmap *pixmap, GdkPixmap *mask) { - GtkNotebookPage *oldpage; + GtkWidget *page_widget; GtkWidget *pixwid; - oldpage = GTK_NOTEBOOK (widget)->cur_page; + page_widget = gtk_notebook_get_nth_page (notebook, page_num); + + pixwid = gtk_object_get_data (GTK_OBJECT (page_widget), "tab_pixmap"); + gtk_pixmap_set (GTK_PIXMAP (pixwid), pixmap, mask); + + pixwid = gtk_object_get_data (GTK_OBJECT (page_widget), "menu_pixmap"); + gtk_pixmap_set (GTK_PIXMAP (pixwid), pixmap, mask); +} - if (page == oldpage) +static void +page_switch (GtkWidget *widget, GtkNotebookPage *page, gint page_num) +{ + GtkNotebook *notebook = GTK_NOTEBOOK (widget); + gint old_page_num = gtk_notebook_get_current_page (notebook); + + if (page_num == old_page_num) return; - pixwid = ((GtkBoxChild*) - (GTK_BOX (page->tab_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_open, book_open_mask); - pixwid = ((GtkBoxChild*) - (GTK_BOX (page->menu_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_open, book_open_mask); - - if (oldpage) - { - pixwid = ((GtkBoxChild*) - (GTK_BOX (oldpage->tab_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_closed, book_closed_mask); - pixwid = ((GtkBoxChild*) - (GTK_BOX (oldpage->menu_label)->children->data))->widget; - gtk_pixmap_set (GTK_PIXMAP (pixwid), book_closed, book_closed_mask); - } + + set_page_pixmaps (notebook, page_num, book_open, book_open_mask); + + if (old_page_num != -1) + set_page_pixmaps (notebook, old_page_num, book_closed, book_closed_mask); } static void @@ -6589,19 +6592,25 @@ create_pages (GtkNotebook *notebook, gint start, gint end) label_box = gtk_hbox_new (FALSE, 0); pixwid = gtk_pixmap_new (book_closed, book_closed_mask); + gtk_object_set_data (GTK_OBJECT (child), "tab_pixmap", pixwid); + gtk_box_pack_start (GTK_BOX (label_box), pixwid, FALSE, TRUE, 0); gtk_misc_set_padding (GTK_MISC (pixwid), 3, 1); label = gtk_label_new (buffer); gtk_box_pack_start (GTK_BOX (label_box), label, FALSE, TRUE, 0); gtk_widget_show_all (label_box); + menu_box = gtk_hbox_new (FALSE, 0); pixwid = gtk_pixmap_new (book_closed, book_closed_mask); + gtk_object_set_data (GTK_OBJECT (child), "menu_pixmap", pixwid); + gtk_box_pack_start (GTK_BOX (menu_box), pixwid, FALSE, TRUE, 0); gtk_misc_set_padding (GTK_MISC (pixwid), 3, 1); label = gtk_label_new (buffer); gtk_box_pack_start (GTK_BOX (menu_box), label, FALSE, TRUE, 0); gtk_widget_show_all (menu_box); + gtk_notebook_append_page_menu (notebook, child, label_box, menu_box); } } @@ -6628,6 +6637,7 @@ standard_notebook (GtkButton *button, gint i; gtk_notebook_set_show_tabs (notebook, TRUE); + gtk_notebook_set_show_border (notebook, TRUE); gtk_notebook_set_scrollable (notebook, FALSE); if (g_list_length (notebook->children) == 15) for (i = 0; i < 10; i++) @@ -6641,6 +6651,20 @@ notabs_notebook (GtkButton *button, gint i; gtk_notebook_set_show_tabs (notebook, FALSE); + gtk_notebook_set_show_border (notebook, TRUE); + if (g_list_length (notebook->children) == 15) + for (i = 0; i < 10; i++) + gtk_notebook_remove_page (notebook, 5); +} + +static void +borderless_notebook (GtkButton *button, + GtkNotebook *notebook) +{ + gint i; + + gtk_notebook_set_show_tabs (notebook, FALSE); + gtk_notebook_set_show_border (notebook, FALSE); if (g_list_length (notebook->children) == 15) for (i = 0; i < 10; i++) gtk_notebook_remove_page (notebook, 5); @@ -6651,6 +6675,7 @@ scrollable_notebook (GtkButton *button, GtkNotebook *notebook) { gtk_notebook_set_show_tabs (notebook, TRUE); + gtk_notebook_set_show_border (notebook, TRUE); gtk_notebook_set_scrollable (notebook, TRUE); if (g_list_length (notebook->children) == 5) create_pages (notebook, 6, 15); @@ -6689,7 +6714,8 @@ create_notebook (void) { { "Standard", standard_notebook }, { "No tabs", notabs_notebook }, - { "Scrollable", scrollable_notebook } + { "Borderless", borderless_notebook }, + { "Scrollable", scrollable_notebook }, }; if (!window) @@ -6753,7 +6779,7 @@ create_notebook (void) label = gtk_label_new ("Notebook Style :"); gtk_box_pack_start (GTK_BOX (box2), label, FALSE, TRUE, 0); - omenu = build_option_menu (items, 3, 0, sample_notebook); + omenu = build_option_menu (items, G_N_ELEMENTS (items), 0, sample_notebook); gtk_box_pack_start (GTK_BOX (box2), omenu, FALSE, TRUE, 0); button = gtk_button_new_with_label ("Show all Pages"); |