diff options
77 files changed, 11569 insertions, 3110 deletions
@@ -1,5 +1,9 @@ 2003-01-20 Marco Pesenti Gritti <marco@it.gnome.org> + * Merge eog-menu-api branch + +2003-01-20 Marco Pesenti Gritti <marco@it.gnome.org> + * embed/ephy-embed-event.c: (free_g_value), (ephy_embed_event_init), (ephy_embed_event_get_property): * embed/ephy-embed-event.h: @@ -40,6 +44,168 @@ * embed/mozilla/FilePicker.cpp: Api change +2003-01-20 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/ui/epiphany-ui.xml.in: + * src/ephy-spinner-action.c: (create_tool_item): + * src/ephy-tab.c: (ephy_tab_init), (ephy_tab_finalize), + (ephy_tab_get_event), (ephy_tab_set_event), + (ephy_tab_show_embed_popup), (ephy_tab_dom_mouse_down_cb): + * src/ephy-tab.h: + * src/ephy-window.c: (setup_window), (ephy_window_init), + (ephy_window_finalize), (ephy_window_get_active_embed): + * src/ephy-window.h: + * src/popup-commands.c: (get_event_info), + (popup_cmd_link_in_new_window), (popup_cmd_link_in_new_tab), + (popup_cmd_image_in_new_tab), (popup_cmd_image_in_new_window), + (popup_cmd_add_link_bookmark), (popup_cmd_frame_in_new_tab), + (popup_cmd_frame_in_new_window), (popup_cmd_copy_to_clipboard), + (popup_cmd_copy_page_location), (popup_cmd_copy_email), + (popup_cmd_copy_link_location), (save_property_url), + (popup_cmd_open_link), (popup_cmd_download_link), + (popup_cmd_save_image_as), (background_download_completed), + (popup_cmd_set_image_as_background), + (popup_cmd_copy_image_location), (popup_cmd_save_background_as), + (popup_cmd_open_frame), (popup_cmd_open_image): + * src/popup-commands.h: + + Implement context menus + +2003-01-19 Marco Pesenti Gritti <marco@it.gnome.org> + + * lib/widgets/ephy-spinner.c: (ephy_spinner_expose): + * src/ephy-favicon-action.c: (create_tool_item), + (each_url_get_data_binder), (favicon_drag_data_get_cb), + (ephy_favicon_action_sync_icon), (connect_proxy), + (ephy_favicon_action_set_property), + (ephy_favicon_action_get_property), + (ephy_favicon_action_class_init), (ephy_favicon_action_init): + * src/ephy-favicon-action.h: + * src/ephy-location-action.c: (ephy_location_action_get_widget): + * src/ephy-location-action.h: + * src/ephy-navigation-action.c: + * src/ephy-spinner-action.c: (ephy_spinner_action_sync_throbbing), + (create_tool_item), (connect_proxy), + (ephy_spinner_action_set_property), + (ephy_spinner_action_get_property), + (ephy_spinner_action_class_init), (ephy_spinner_action_init): + * src/ephy-spinner-action.h: + * src/ephy-window.c: (setup_window), (update_nav_control): + * src/toolbar.c: (toolbar_setup_actions), + (toolbar_activate_location), (toolbar_spinner_start), + (toolbar_spinner_stop), (toolbar_set_location), + (toolbar_update_favicon), (toolbar_get_location), + (toolbar_update_navigation_actions): + * src/toolbar.h: + + Complete toolbar implementation. + +2003-01-18 Marco Pesenti Gritti <marco@it.gnome.org> + + * lib/ephy-gui.c: (ephy_gui_menu_position_under_widget): + * lib/widgets/ephy-arrow-toolbutton.c: (popup_menu_under_arrow): + * src/ephy-location-action.c: (create_tool_item), + (location_url_activate_cb), (connect_proxy), + (ephy_location_action_class_init): + * src/ephy-location-action.h: + * src/ephy-shell.c: (ephy_shell_get_autocompletion): + * src/ephy-spinner-action.c: (create_tool_item): + * src/toolbar.c: (toolbar_setup_widgets), (go_location_cb), + (toolbar_setup_actions): + + Make location and navigation buttons works correctly. + +2003-01-18 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/ui/Makefile.am: + * lib/widgets/Makefile.am: + * lib/widgets/ephy-arrow-toolbutton.c: + (ephy_arrow_toolbutton_get_type), + (ephy_arrow_toolbutton_class_init), (button_state_changed_cb), + (popup_menu_under_arrow), (menu_deactivated_cb), + (arrow_button_press_event_cb), (arrow_key_press_event_cb), + (ephy_arrow_toolbutton_init), (ephy_arrow_toolbutton_finalize), + (ephy_arrow_toolbutton_get_menu): + * lib/widgets/ephy-arrow-toolbutton.h: + * src/Makefile.am: + * src/ephy-navigation-action.c: (ephy_navigation_action_get_type), + (new_history_menu_item), (activate_back_or_forward_menu_item_cb), + (activate_up_menu_item_cb), (setup_back_or_forward_menu), + (setup_up_menu), (menu_activated_cb), (connect_proxy), + (ephy_navigation_action_set_property), + (ephy_navigation_action_get_property), + (ephy_navigation_action_class_init), (ephy_navigation_action_init): + * src/ephy-navigation-action.h: + * src/ephy-window.c: (ephy_window_init): + * src/toolbar.c: (toolbar_setup_actions), (toolbar_set_window), + (toolbar_init): + + Implement back/forward + +2003-01-17 Marco Pesenti Gritti <marco@it.gnome.org> + + * data/ui/Makefile.am: + * data/ui/epiphany-ui.xml.in: + * src/Makefile.am: + * src/ephy-window.c: (add_widget), (setup_window), + (ephy_window_init), (ephy_window_set_chrome): + * src/toolbar.c: (toolbar_setup_widgets), (add_widget), + (toolbar_set_window), (toolbar_setup_actions), (toolbar_init), + (toolbar_finalize), (toolbar_set_visibility): + + Make some toolbar widgets work again + +2003-01-16 Marco Pesenti Gritti <marco@it.gnome.org> + + * configure.in: + * data/ui/Makefile.am: + * data/ui/epiphany-ui.xml.in: + * embed/mozilla/GlobalHistory.cpp: + * lib/Makefile.am: + * src/Makefile.am: + * src/ephy-favorites-menu.c: (ephy_favorites_menu_init), + (ephy_favorites_menu_clean), (ephy_favorites_menu_finalize_impl), + (ephy_favorites_menu_set_property), (ephy_favorites_menu_rebuild): + * src/ephy-favorites-menu.h: + * src/ephy-nautilus-view.c: (gnv_bonobo_control_activate_cb), + (gnv_popup_cmd_frame_in_new_window): + * src/ephy-window.c: (add_widget), (setup_window), + (setup_popup_factory), (ephy_window_init), (ephy_window_finalize), + (ephy_window_set_chrome), (ephy_window_activate_location), + (update_status_message), (update_progress), (update_security), + (update_nav_control), (update_location_control), + (update_favicon_control), (update_spinner_control), + (save_old_embed_status), (ephy_window_get_toolbar): + * src/ppview-toolbar.c: (ppview_toolbar_set_window), + (ppview_toolbar_init), (ppview_toolbar_finalize), + (toolbar_update_sensitivity), (toolbar_cmd_ppv_goto_first), + (toolbar_cmd_ppv_goto_last), (toolbar_cmd_ppv_go_back), + (toolbar_cmd_ppv_go_forward), (toolbar_cmd_ppv_close): + * src/ppview-toolbar.h: + * src/statusbar.c: (statusbar_get_type), (statusbar_class_init), + (create_statusbar_security_icon), (create_statusbar_progress), + (statusbar_init), (statusbar_new), (statusbar_set_message): + * src/statusbar.h: + * src/toolbar.c: (toolbar_get_type), (toolbar_class_init), + (toolbar_setup_favicon), (toolbar_setup_location_entry), + (toolbar_set_window), (toolbar_init), (toolbar_finalize), + (toolbar_set_visibility), (toolbar_button_set_sensitive), + (toolbar_get_location): + * src/toolbar.h: + * src/window-commands.c: + * src/window-commands.h: + + More menu work ... + +2003-01-14 Marco Pesenti Gritti <marco@it.gnome.org> + + * src/ephy-window.c: + * src/ephy-window.h: + * src/window-commands.c: + * src/window-commands.h: + + Some work on the new menu stuff + 2003-01-13 Marco Pesenti Gritti <marco@it.gnome.org> * embed/mozilla/FilePicker.cpp: @@ -2,12 +2,10 @@ To do: - implement phoenix like popup blocking / make popups less annoying - loading feedback on tabs -- create print preview toolbar only when necessary - embed dialogs crashes when the window has been closed - save bookmarks dialog state (current keyword) - show bookmarks updated content - temporary bookmarks, maybe an expire checkbox in new bookmark dialog ? -- titles in history for hosts too Done: @@ -24,3 +22,5 @@ Done: * history scoring for autocompletion * urls like www.gnome.org and gnome.org should use same folder in history * drop items from history when they are not visited since some time +* create print preview toolbar only when necessary +* titles in history for hosts too diff --git a/configure.in b/configure.in index 9922826b9..6f5d36651 100644 --- a/configure.in +++ b/configure.in @@ -162,8 +162,8 @@ data/art/Makefile data/ui/Makefile data/starthere/Makefile lib/Makefile +lib/egg/Makefile lib/widgets/Makefile -lib/toolbar/Makefile embed/Makefile embed/mozilla/Makefile src/Makefile diff --git a/data/ui/Makefile.am b/data/ui/Makefile.am index 658ebf3f1..c56bceda3 100644 --- a/data/ui/Makefile.am +++ b/data/ui/Makefile.am @@ -1,6 +1,7 @@ -uixmldir = $(datadir)/gnome-2.0/ui +uixmldir = $(pkgdatadir) uixml_in_files = epiphany-ui.xml.in \ - nautilus-epiphany-view.xml.in + nautilus-epiphany-view.xml.in \ + epiphany-toolbar.xml.in uixml_DATA = $(uixml_in_files:.xml.in=.xml) diff --git a/data/ui/epiphany-toolbar.xml.in b/data/ui/epiphany-toolbar.xml.in new file mode 100644 index 000000000..0a46f0fe8 --- /dev/null +++ b/data/ui/epiphany-toolbar.xml.in @@ -0,0 +1,15 @@ +<Root> +<dockitem name="toolbar1"> + <toolitem name="ViewBackTItem" verb="NavigationBack"/> + <toolitem name="ViewForwardTItem" verb="NavigationForward"/> + <toolitem name="ViewStopTItem" verb="ViewStop"/> + <toolitem name="ViewReloadTItem" verb="ViewReload"/> + <separator name="ToolbarSep1"/> + <toolitem name="GoHomeTItem" verb="GoHome"/> + <separator name="ToolbarSep2"/> + <toolitem name="FaviconTItem" verb="Favicon"/> + <toolitem name="LocationTItem" verb="Location"/> + <toolitem name="SpinnerTItem" verb="Spinner"/> +</dockitem> +</Root> + diff --git a/data/ui/epiphany-ui.xml.in b/data/ui/epiphany-ui.xml.in index 0927957a5..2a47b0252 100644 --- a/data/ui/epiphany-ui.xml.in +++ b/data/ui/epiphany-ui.xml.in @@ -1,458 +1,150 @@ <Root> - -<commands> - <cmd name="FileOpen" _label="Open" - _tip="Open a file" pixtype="stock" pixname="gtk-open" accel="*Control*O"/> - - <cmd name="FileSaveAs" _label="Save As" - _tip="Save the current file with a different name" - pixtype="stock" pixname="gtk-save-as" - accel="*Shift**Control*S"/> - - <cmd name="FilePrint" _label="Print" - _tip="Print the current file" pixtype="stock" pixname="gtk-print" - accel="*Control*P"/> - - <cmd name="FileCloseTab" _tip="Close the current tab" - pixtype="stock" pixname="gtk-close"/> - - <cmd name="FileCloseWindow" _tip="Close the current window"/> - - <cmd name="EditCut" _label="Cut" _tip="Cut the selection" - pixtype="stock" pixname="gtk-cut"/> - - <cmd name="EditCopy" _label="Copy" - _tip="Copy the selection" pixtype="stock" pixname="gtk-copy"/> - - <cmd name="EditPaste" _label="Paste" - _tip="Paste the clipboard" pixtype="stock" pixname="gtk-paste"/> - - <cmd name="EditSelectAll" _label="Select All" _tip="Select the entire document" - accel="*Control*A"/> - - <cmd name="EditFind" _label="Find" _tip="Search for a string" - pixtype="stock" pixname="gtk-find" accel="*Control*F"/> - - <cmd name="Zoom In" _label="Zoom In" - _tip="Show the contents in more detail"/> - <cmd name="Zoom Out" _label="Zoom Out" - _tip="Show the contents in less detail"/> - <cmd name="Zoom Normal" _label="Normal Size" - _tip="Show the contents at the normal size"/> - - <cmd name="SettingsPreferences" _label="Preferences" _tip="Configure the application" - pixtype="stock" pixname="gtk-preferences"/> - - <cmd name="SettingsToolbarEditor" _label="Toolbar" _tip="Edit the main toolbar"/> - - <cmd name="HelpContents" _label="Contents" _tip="Open the Epiphany manual" - accel="F1"/> - - <cmd name="About" _label="About..." _tip="About this application" - pixtype="stock" pixname="About"/> - - <cmd name="BookmarksAddDefault" _label="Add bookmark" - _tip="Add a bookmark to the default folder"/> - - <cmd name="BookmarksEdit" _label="Edit bookmarks" - _tip="Open a bookmarks editor"/> - - <cmd name="GoBack" _label="_Back" - sensitive="0"/> - - <cmd name="GoUp" _label="_Up" - sensitive="0"/> - - <cmd name="GoHome" _label="_Home"/> - - <cmd name="GoMyportal" _label="_My portal"/> - - <cmd name="GoForward" _label="_Forward" - sensitive="0"/> - - <cmd name="GoStop" _label="_Stop" - sensitive="0" - _tip="Stop current data transfer"/> - - <cmd name="GoReload" _label="_Reload" - _tip="Display the latest content of the current page"/> - - <cmd name="GoGo" _label="_Go" - _tip="Load the URL in the location entry"/> - - <cmd name="EPOpenLink" _label="Open"/> - - <cmd name="EPOpenInNewWindow" _label="Open in New Window"/> - - <cmd name="EPOpenInNewTab" _label="Open in New Tab"/> - - <cmd name="EPCopyLinkLocation" _label="Copy Link Location"/> - - <cmd name="EPCopyEmail" _label="Copy Email Address"/> - - <cmd name="EPDownloadLink" _label="Download Link"/> - - <cmd name="EPAddBookmark" _label="Add Bookmark"/> - - <cmd name="EPOpenImage" _label="Open Image"/> - - <cmd name="EPOpenImageInNewWindow" _label="Open Image in New Window"/> - - <cmd name="EPOpenImageInNewTab" _label="Open Image in New Tab"/> - - <cmd name="EPSaveImageAs" _label="Save Image As..."/> - - <cmd name="EPSetImageAsBackground" _label="Use Image as Background"/> - - <cmd name="EPCopyImageLocation" _label="Copy Image Location"/> - - <cmd name="DPCopyLocation" _label="Copy Page location"/> - - <cmd name="DPOpenFrame" _label="Open Frame"/> - - <cmd name="DPOpenFrameInNewWindow" _label="Open Frame in New Window"/> - - <cmd name="DPOpenFrameInNewTab" _label="Open Frame in New Tab"/> - - <cmd name="DPReloadFrame" _label="Reload Frame"/> - - <cmd name="DPAddFrameBookmark" _label="Add Bookmark for Frame"/> - - <cmd name="DPSavePageAs" _label="Save Page As..."/> - - <cmd name="DPSaveBackgroundAs" _label="Save Background As..."/> - - <cmd name="DPAddPageBookmark" verb="Add Bookmark"/> - - <cmd name="PPVGotoFirst" _label="First"/> - - <cmd name="PPVGotoLast" _label="Last"/> - - <cmd name="PPVGoBack" _label="Previous"/> - - <cmd name="PPVGoForward" _label="Next"/> - -</commands> - -<keybindings> - <accel name="*Control*S" verb="FileSaveAs"/> -</keybindings> - <menu> - -<submenu name="File" _label="_File"> - - <menuitem name="FileNewWindow" verb="" - _label="_New Window" - pixtype="stock" pixname="gtk-new" - accel="*Control*n"/> - - <menuitem name="FileNewTab" verb="" _label="New _Tab" accel="*Control*t"/> - - <menuitem name="FileOpen" verb="" _label="_Open..."/> - - <separator/> - - <menuitem name="FileSaveAs" verb="" _label="Save _As..."/> - - <separator/> - - <menuitem name="FilePrint" verb="" _label="_Print..."/> - <menuitem name="FileSendTo" verb="" - pixtype="stock" pixname="epiphany-send-link" - _label="S_end To..."/> - - <separator/> - - <menuitem name="BookmarksAddDefault" verb="" _label="_Add Bookmark" - _tip="Add a bookmark for the current location to the default folder" - pixtype="stock" pixname="gtk-add" accel="*Control*d"/> - - <separator/> - - <menuitem name="FileCloseTab" verb="" _label="_Close Tab" accel="*Control*W"/> - - <menuitem name="FileCloseWindow" verb="" _label="Close _Window" accel="*Shift**Control*W"/> - +<submenu name="FileMenu" verb="File"> + <menuitem name="FileNewWindowMenu" verb="FileNewWindow"/> + <menuitem name="FileNewTabMenu" verb="FileNewTab"/> + <menuitem name="FileOpenMenu" verb="FileOpen"/> + <separator name="FileSep1"/> + <menuitem name="FileSaveAsMenu" verb="FileSaveAs"/> + <separator name="FileSep2"/> + <menuitem name="FilePrintMenu" verb="FilePrint"/> + <menuitem name="FileSendToMenu" verb="FileSendTo"/> + <separator name="FileSep3"/> + <menuitem name="FileAddBookmarkMenu" verb="FileAddBookmark"/> + <separator name="FileSep4"/> + <menuitem name="FileCloseTabMenu" verb="FileCloseTab"/> + <menuitem name="FileCloseWindowMenu" verb="FileCloseWindow"/> </submenu> -<submenu name="Edit" _label="_Edit"> - - <menuitem name="EditCut" verb="" _label="Cu_t" accel="*Control*X"/> - - <menuitem name="EditCopy" verb="" _label="_Copy" accel="*Control*c"/> - - <menuitem name="EditPaste" verb="" _label="_Paste" accel="*Control*v"/> - - <separator/> - - <menuitem name="EditSelectAll" verb="" _label="Select _All"/> - - <separator/> - - <menuitem name="EditFind" verb="" _label="_Find..."/> - <menuitem name="EditFindNext" verb="" - accel="*Control*G" _label="Find Ne_xt"/> - <menuitem name="EditFindPrev" verb="" - accel="*Shift**Control*G" _label="Find Pre_vious"/> - - <separator/> - - <menuitem name="PDM" verb="ToolsPDM" _label="P_ersonal Data"/> - - <menuitem name="EditToolbar" - _label="T_oolbar" - verb="SettingsToolbarEditor"/> - - <menuitem name="EditPrefs" - _label="P_references" - _tip="Edit Ephy preferences" - pixtype="stock" pixname="gtk-preferences" - verb="EditPrefs"/> +<submenu name="EditMenu" verb="Edit"> + <menuitem name="EditCutMenu" verb="EditCut"/> + <menuitem name="EditCopyMenu" verb="EditCopy"/> + <menuitem name="EditPasteMenu" verb="EditPaste"/> + <separator name="EditSep1"/> + <menuitem name="EditSelectAllMenu" verb="EditSelectAll"/> + <separator name="EditSep2"/> + <menuitem name="EditFindMenu" verb="EditFind"/> + <menuitem name="EditFindNextMenu" verb="EditFindNext"/> + <menuitem name="EditFindPrevMenu" verb="EditFindPrev"/> + <separator name="EditSep3"/> + <menuitem name="EditPersonalDataMenu" verb="EditPersonalData"/> + <menuitem name="EditToolbarMenu" verb="EditToolbar"/> + <menuitem name="EditPrefsMenu" verb="EditPrefs"/> </submenu> -<submenu name="View" _label="_View"> - - <menuitem name="GoStop" - pixtype="stock" pixname="gtk-stop" - verb="" accel="Escape"/> - - <menuitem name="GoReload" - pixtype="stock" pixname="gtk-refresh" - verb="" accel="*Control*R"/> - - <separator/> - - <menuitem name="View Toolbar" id="View Toolbar" type="toggle" - _label="_Toolbar" verb="" accel="*Shift**Control*T"/> - - <menuitem name="View Statusbar" id="View Statusbar" - type="toggle" _label="St_atusbar" verb=""/> - - <menuitem name="View Fullscreen" id="View Fullscreen" - type="toggle" _label="_Fullscreen" verb="" accel="F11"/> - - <separator/> - - <menuitem name="Zoom In" - _label="Zoom _In" accel="*Control*plus" - pixtype="stock" pixname="zoom-in" - verb="Zoom In"/> - - <menuitem name="Zoom Out" - _label="Zoom _Out" accel="*Control*minus" - pixtype="stock" pixname="zoom-out" - verb="Zoom Out"/> - - <menuitem name="Zoom Normal" - _label="_Normal Size" - pixtype="stock" pixname="zoom-100" - verb="Zoom Normal"/> - - <separator/> - - <placeholder name="EncodingMenuPlaceholder"/> - - <menuitem name="Page Source" - _label="_Page Source" - verb="ViewPageSource"/> - +<submenu name="ViewMenu" verb="View"> + <menuitem name="ViewStopMenu" verb="ViewStop"/> + <menuitem name="ViewReloadMenu" verb="ViewReload"/> + <separator name="ViewSep1"/> + <menuitem name="ViewStatusbarMenu" verb="ViewStatusbar"/> + <menuitem name="ViewFullscreenMenu" verb="ViewFullscreen"/> + <separator name="ViewSep2"/> + <menuitem name="ViewZoomInMenu" verb="ViewZoomIn"/> + <menuitem name="ViewZoomOutMenu" verb="ViewZoomOut"/> + <menuitem name="ViewZoomNormalMenu" verb="ViewZoomNormal"/> + <separator name="ViewSep3"/> + <placeholder name="ViewEncodingPlaceholder"/> + <menuitem name="ViewPageSourceMenu" verb="ViewPageSource"/> </submenu> -<submenu name="Go" _label="_Go"> - <menuitem name="GoBack" - pixtype="stock" pixname="gtk-go-back" - verb="" accel="*Alt*Left"/> - - <menuitem name="GoForward" - pixtype="stock" pixname="gtk-go-forward" - verb="" accel="*Alt*Right"/> - - <menuitem name="GoUp" - pixtype="stock" pixname="gtk-go-up" - verb="" accel="*Alt*Up"/> - - <separator/> - - <menuitem name="GoHome" - pixtype="stock" pixname="gtk-home" - verb="" accel="*Alt*Home"/> - - <menuitem name="GoLocation" _label="_Location..." - verb="" accel="*Ctrl*l"/> - - <separator/> - - <menuitem name="History" verb="ToolsHistory" - _label="_History" accel="*Control*H"/> - - <menuitem name="BookmarksEdit" verb="" _label="_Bookmarks" - accel="*Control*b"/> - - <placeholder name="Favorites" delimit="top"/> +<submenu name="GoMenu" verb="Go"> + <menuitem name="GoBackMenu" verb="GoBack"/> + <menuitem name="GoForwardMenu" verb="GoForward"/> + <menuitem name="GoUpMenu" verb="GoUp"/> + <separator name="GoSep1"/> + <menuitem name="GoHomeMenu" verb="GoHome"/> + <menuitem name="GoLocationMenu" verb="GoLocation"/> + <separator name="GoSep2"/> + <menuitem name="GoHistoryMenu" verb="GoHistory"/> + <menuitem name="GoBookmarksMenu" verb="GoBookmarks"/> + <placeholder name="GoFavorites"> + <separator name="GoSep3"/> + </placeholder> </submenu> -<submenu name="Tabs" _label="_Tabs"> - <menuitem name="Previous Tab" verb="TabsPrevious" _label="_Previous Tab" - accel="*Control*Page_Up"/> - <menuitem name="Next Tab" verb="TabsNext" _label="_Next Tab" - accel="*Control*Page_Down"/> - <separator/> - <menuitem name="Tab Left" verb="TabsMoveLeft" _label="Move Tab _Left" - accel="*Shift**Control*Page_Up"/> - <menuitem name="Tab Right" verb="TabsMoveRight" _label="Move Tab _Right" - accel="*Shift**Control*Page_Down"/> - <menuitem name="Move Tab to New Window" verb="TabsDetach" _label="_Detach Tab" - accel="*Shift**Control*m"/> +<submenu name="TabsMenu" verb="Tabs"> + <menuitem name="TabsPreviousMenu" verb="TabsPrevious"/> + <menuitem name="TabsNextMenu" verb="TabsNext"/> + <separator name="TabsSep1"/> + <menuitem name="TabsMoveLeftMenu" verb="TabsMoveLeft"/> + <menuitem name="TabsMoveRightMenu" verb="TabsMoveRight"/> + <menuitem name="TabsDetachMenu" verb="TabsDetach"/> </submenu> -<submenu name="Help" _label="_Help"> - - <menuitem name="HelpContents" verb="" - pixtype="stock" pixname="gtk-help" - _label="_Contents"/> - - <menuitem name="About" verb="" _label="_About"/> - +<submenu name="HelpMenu" verb="Help"> + <menuitem name="HelpAboutMenu" verb="HelpAbout"/> </submenu> - </menu> <popups> +<popup name="EphyEmbedInputPopup" verb="FakeToplevel"> + <menuitem name="EditCutIP" verb="EditCut"/> + <menuitem name="EditCopyIP" verb="EditCopy"/> + <menuitem name="EditPasteIP" verb="EditPaste"/> +</popup> + +<popup name="EphyDocumentPopup" verb="FakeToplevel"> + <menuitem name="GoBackDP" verb="GoBack"/> + <menuitem name="GoForwardDP" verb="GoForward"/> + <menuitem name="GoReloadDP" verb="ViewReload"/> + <separator name="DPSep1"/> + <menuitem name="SavePageAsDP" verb="FileSaveAs"/> + <menuitem name="SaveBackgroundAsDP" verb="SaveBackgroundAs"/> + <menuitem name="AddPageBookmarkDP" verb="FileAddBookmark"/> + <menuitem name="CopyPageLocationDP" verb="CopyPageLocation"/> +</popup> + +<popup name="EphyFramedDocumentPopup" verb="FakeToplevel"> + <menuitem name="GoBackFDP" verb="GoBack"/> + <menuitem name="GoForwardFDP" verb="GoForward"/> + <menuitem name="GoReloadFDP" verb="ViewReload"/> + <separator name="FDPSep1"/> + <menuitem name="SavePageAsFDP" verb="FileSaveAs"/> + <menuitem name="SaveBackgroundAsFDP" verb="SaveBackgroundAs"/> + <menuitem name="AddPageBookmarkFDP" verb="FileAddBookmark"/> + <menuitem name="CopyPageLocationFDP" verb="CopyPageLocation"/> + <separator name="FDBSep2"/> + <menuitem name="OpenFrameFDP" verb="OpenFrame"/> + <menuitem name="OpenFrameInNewWindowFDP" verb="OpenFrameInNewWindow"/> + <menuitem name="OpenFrameInNewTabFDP" verb="OpenFrameInNewTab"/> +</popup> + +<popup name="EphyLinkPopup" verb="FakeToplevel"> + <menuitem name="OpenLinkLP" verb="OpenLink"/> + <menuitem name="OpenLinkInNewWindowLP" verb="OpenLinkInNewWindow"/> + <menuitem name="OpenLinkInNewTabLP" verb="OpenLinkInNewTab"/> + <menuitem name="DownloadLinkLP" verb="DownloadLink"/> + <menuitem name="AddLinkBookmarkLP" verb="AddLinkBookmark"/> + <menuitem name="CopyLinkLocationLP" verb="CopyLinkLocation"/> + <menuitem name="CopyEmailLinkLP" verb="CopyEmail"/> +</popup> + +<popup name="EphyImagePopup" verb="FakeToplevel"> + <menuitem name="OpenImageIP" verb="OpenImage"/> + <menuitem name="OpenImageInNewWindowIP" verb="OpenImageInNewWindow"/> + <menuitem name="OpenImageInNewTabIP" verb="OpenImageInNewTab"/> + <menuitem name="SaveImageAsIP" verb="SaveImageAs"/> + <menuitem name="SetImageAsBackgroundIP" verb="SetImageAsBackground"/> + <menuitem name="CopyImageLocationIP" verb="CopyImageLocation"/> +</popup> + +<popup name="EphyImageLinkPopup" verb="FakeToplevel"> + <menuitem name="OpenLinkILP" verb="OpenLink"/> + <menuitem name="OpenLinkInNewWindowILP" verb="OpenLinkInNewWindow"/> + <menuitem name="OpenLinkInNewTabILP" verb="OpenLinkInNewTab"/> + <menuitem name="DownloadLinkILP" verb="DownloadLink"/> + <menuitem name="AddLinkBookmarkILP" verb="AddLinkBookmark"/> + <menuitem name="CopyLinkLocationILP" verb="CopyLinkLocation"/> + <menuitem name="CopyEmailLinkILP" verb="CopyEmail"/> + <separator name="LPSep1"/> + <menuitem name="OpenImageILP" verb="OpenImage"/> + <menuitem name="OpenImageInNewWindowILP" verb="OpenImageInNewWindow"/> + <menuitem name="OpenImageInNewTabILP" verb="OpenImageInNewTab"/> + <menuitem name="SaveImageAsILP" verb="SaveImageAs"/> + <menuitem name="SetImageAsBackgroundILP" verb="SetImageAsBackground"/> + <menuitem name="CopyImageLocationILP" verb="CopyImageLocation"/> +</popup> - <popup name="EphyEmbedInputPopup"> - <menuitem name="EditCut" - pixtype="stock" pixname="gtk-cut" - verb=""/> - <menuitem name="EditCopy" - pixtype="stock" pixname="gtk-copy" - verb=""/> - <menuitem name="EditPaste" - pixtype="stock" pixname="gtk-paste" - verb=""/> - </popup> - - <popup name="EphyEmbedDocumentPopup"> - <placeholder name="NavigationItems"> - <menuitem name="GoBack" - pixtype="stock" pixname="gtk-go-back" - verb=""/> - - <menuitem name="GoForward" - pixtype="stock" pixname="gtk-go-forward" - verb=""/> - - <menuitem name="GoReload" - pixtype="stock" pixname="gtk-refresh" - verb=""/> - - <separator/> - </placeholder> - - <menuitem name="DPSavePageAs" - pixtype="stock" pixname="gtk-save" - verb=""/> - - <menuitem name="DPSaveBackgroundAs" verb=""/> - - <menuitem name="DPViewSource" _label="Page Source" - verb="ViewPageSource"/> - - <menuitem name="DPAddPageBookmark" - verb=""/> - - <menuitem name="DPCopyLocation" - pixtype="stock" pixname="gtk-copy" - verb=""/> - - <placeholder name="FrameItems"> - <separator/> - <menuitem name="DPOpenFrame" verb=""/> - <menuitem name="DPOpenFrameInNewWindow" verb=""/> - <menuitem name="DPOpenFrameInNewTab" verb=""/> - <menuitem name="DPReloadFrame" verb=""/> - <menuitem name="DPAddFrameBookmark" verb=""/> - </placeholder> - </popup> - - <popup name="EphyEmbedElementPopup"> - <placeholder name="LinkItems"> - <menuitem name="EPOpenLink" - pixtype="stock" pixname="gtk-open" - verb=""/> - - <menuitem name="EPOpenInNewWindow" verb=""/> - - <menuitem name="EPOpenInNewTab" verb=""/> - - <menuitem name="EPDownloadLink" verb=""/> - - <menuitem name="EPAddBookmark" - pixtype="stock" pixname="gtk-add" - verb=""/> - - <menuitem name="EPCopyLinkLocation" - pixtype="stock" pixname="gtk-copy" - verb=""/> - </placeholder> - <placeholder name="EmailLinkItems"> - <menuitem name="EPCopyEmail" - pixtype="stock" pixname="gtk-copy" - verb=""/> - </placeholder> - <placeholder name="BetweenElements1"> - <separator/> - </placeholder> - - <placeholder name="ImageItems"> - <menuitem name="EPOpenImage" - pixtype="stock" pixname="gtk-open" - verb=""/> - - <menuitem name="EPOpenImageInNewWindow" verb=""/> - <menuitem name="EPOpenImageInNewTab" verb=""/> - - <menuitem name="EPSaveImageAs" - pixtype="stock" pixname="gtk-save" - verb=""/> - - <menuitem name="EPSetImageAsBackground" verb=""/> - - <menuitem name="EPCopyImageLocation" - pixtype="stock" pixname="gtk-copy" - verb=""/> - </placeholder> - </popup> </popups> - -<dockitem name="Toolbar" behavior="exclusive" config="0"> -</dockitem> - -<dockitem name="PrintPreview" behavior="exclusive"> - <toolitem name="PPVGotoFirst" - pixtype="stock" pixname="gtk-goto-first" - verb="PPVGotoFirst"/> - <toolitem name="PPVGoBack" - pixtype="stock" pixname="gtk-go-back" - verb="PPVGoBack"/> - <toolitem name="PPVGoForward" - pixtype="stock" pixname="gtk-go-forward" - priority="1" - verb="PPVGoForward"/> - <toolitem name="PPVGotoLast" - pixtype="stock" pixname="gtk-goto-last" - verb="PPVGotoLast"/> - <toolitem name="Close" _label="Close" - pixtype="stock" pixname="gtk-close" - priority="1" - verb="PPVClose"/> -</dockitem> - -<status resize_grip="0"> - <item name="main"/> - <control name="SecurityIconWrapper"/> - <control name="ProgressWrapper"/> -</status> - </Root> diff --git a/lib/Makefile.am b/lib/Makefile.am index d131235bb..7d324f0e9 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = widgets toolbar +SUBDIRS = widgets egg INCLUDES = \ $(WARN_CFLAGS) \ @@ -59,7 +59,7 @@ libephy_la_SOURCES = \ libephy_la_LIBADD = \ $(top_builddir)/lib/widgets/libephywidgets.la \ - $(top_builddir)/lib/toolbar/libephytoolbar.la + $(top_builddir)/lib/egg/libegg.la BUILT_SOURCES=ephy-marshal.c ephy-marshal.h diff --git a/lib/egg/Makefile.am b/lib/egg/Makefile.am new file mode 100644 index 000000000..93abfd0d3 --- /dev/null +++ b/lib/egg/Makefile.am @@ -0,0 +1,59 @@ +INCLUDES = \ + $(EPIPHANY_DEPENDENCY_CFLAGS) \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DG_DISABLE_DEPRECATED + +noinst_LTLIBRARIES = libegg.la + +libegg_la_SOURCES = \ + egg-action.c \ + egg-action-group.c \ + egg-toggle-action.c \ + egg-radio-action.c \ + egg-markup.c \ + egg-menu-merge.c \ + egg-accel-dialog.c \ + eggradiotoolbutton.c \ + eggtoggletoolbutton.c \ + eggtoolitem.c \ + eggseparatortoolitem.c \ + eggtoolbar.c \ + eggtoolbutton.c \ + eggmarshalers.c + +noinst_HEADERS = \ + egg-menu.h \ + egg-action.h \ + egg-action-group.h \ + egg-toggle-action.h \ + egg-radio-action.h \ + egg-markup.h \ + egg-menu-merge.h \ + egg-accel-dialog.h \ + eggradiotoolbutton.h \ + eggtoggletoolbutton.h \ + eggtoolitem.h \ + eggseparatortoolitem.h \ + eggtoolbar.h \ + eggtoolbutton.h + +eggmarshalers.h: + cd $(srcdir) \ + && $(GLIB_GENMARSHAL) --prefix=_egg_marshal eggmarshalers.list --header > xgen-emh \ + && cp xgen-emh eggmarshalers.h \ + && rm -f xgen-emh xgen-emh~ + +eggmarshalers.c: + cd $(srcdir) \ + && $(GLIB_GENMARSHAL) --prefix=_egg_marshal eggmarshalers.list --body > xgen-emc \ + && cp xgen-emc eggmarshalers.c \ + && rm -f xgen-emc xgen-emc~ + +egg-marshal.c: eggmarshalers.h eggmarshalers.c + +noinst_HEADERS = \ + eggmarshalers.h + +EXTRA_DIST= \ + eggmarshalers.list diff --git a/lib/egg/egg-accel-dialog.c b/lib/egg/egg-accel-dialog.c new file mode 100644 index 000000000..4173cbf02 --- /dev/null +++ b/lib/egg/egg-accel-dialog.c @@ -0,0 +1,332 @@ +#include "egg-accel-dialog.h" + +static void egg_accel_dialog_init (EggAccelDialog *self); +static void egg_accel_dialog_class_init (EggAccelDialogClass *class); + +GType +egg_accel_dialog_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggAccelDialogClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_accel_dialog_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (EggAccelDialog), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_accel_dialog_init, + }; + + type = g_type_register_static (GTK_TYPE_DIALOG, + "EggAccelDialog", + &type_info, 0); + } + return type; +} + +static void +egg_accel_dialog_class_init (EggAccelDialogClass *class) +{ +} + +static void accel_path_selection_changed (GtkTreeSelection *selection, + EggAccelDialog *self); +static void accel_path_set (GtkWidget *button, EggAccelDialog *self); +static void accel_path_reset (GtkWidget *button, EggAccelDialog *self); + +static void +egg_accel_dialog_init (EggAccelDialog *self) +{ + GtkCellRenderer *renderer; + GtkWidget *swin; + GtkWidget *table; + + /* set up the list store for all the accelerators */ + self->accel_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (self->accel_store), + 0, GTK_SORT_ASCENDING); + egg_accel_dialog_rescan_accels (self); + + + swin = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), swin, + TRUE, TRUE, 0); + gtk_widget_show (swin); + + /* set up a two column view of the model in browse selection mode */ + self->accel_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(self->accel_store)); + gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (self->accel_view), TRUE); + gtk_tree_selection_set_mode (gtk_tree_view_get_selection (GTK_TREE_VIEW (self->accel_view)), + GTK_SELECTION_BROWSE); + g_signal_connect_object (gtk_tree_view_get_selection (GTK_TREE_VIEW (self->accel_view)), + "changed", G_CALLBACK (accel_path_selection_changed), + G_OBJECT (self), 0); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->accel_view), + -1, "Path", renderer, + "text", 0, + NULL); + gtk_tree_view_column_set_sort_column_id (gtk_tree_view_get_column (GTK_TREE_VIEW (self->accel_view), 0), 0); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT (renderer), "xalign", 0.0, NULL); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (self->accel_view), + -1, "Accel", renderer, + "text", 1, + NULL); + gtk_tree_view_column_set_sort_column_id (gtk_tree_view_get_column (GTK_TREE_VIEW (self->accel_view), 1), 1); + + gtk_container_add (GTK_CONTAINER (swin), self->accel_view); + gtk_widget_show (self->accel_view); + + table = gtk_table_new (2, 4, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (table), 2); + gtk_table_set_row_spacings (GTK_TABLE (table), 2); + gtk_table_set_col_spacings (GTK_TABLE (table), 2); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (self)->vbox), table, FALSE,TRUE, 0); + gtk_widget_show (table); + + /* widgets for editing accels */ + self->shift_toggle = gtk_check_button_new_with_mnemonic ("S_hift"); + gtk_table_attach (GTK_TABLE (table), self->shift_toggle, + 0, 1, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (self->shift_toggle); + self->ctrl_toggle = gtk_check_button_new_with_mnemonic ("_Ctrl"); + gtk_table_attach (GTK_TABLE (table), self->ctrl_toggle, + 1, 2, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (self->ctrl_toggle); + self->alt_toggle = gtk_check_button_new_with_mnemonic ("_Alt"); + gtk_table_attach (GTK_TABLE (table), self->alt_toggle, + 2, 3, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (self->alt_toggle); + self->key_entry = gtk_entry_new (); + gtk_table_attach (GTK_TABLE (table), self->key_entry, + 0, 3, 1, 2, + GTK_FILL|GTK_EXPAND, GTK_FILL, 0, 0); + gtk_widget_show (self->key_entry); + + /* buttons for changing path */ + self->set_button = gtk_button_new_with_mnemonic ("_Set"); + gtk_table_attach (GTK_TABLE (table), self->set_button, + 3, 4, 0, 1, + GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (self->set_button); + self->reset_button = gtk_button_new_with_mnemonic ("_Reset"); + gtk_table_attach (GTK_TABLE (table), self->reset_button, + 3, 4, 1, 2, + GTK_FILL, GTK_FILL, 0, 0); + /*gtk_widget_show (self->reset_button);*/ + + g_signal_connect_object (self->set_button, "clicked", + G_CALLBACK (accel_path_set), G_OBJECT (self), 0); + g_signal_connect_object (self->reset_button, "clicked", + G_CALLBACK (accel_path_reset), G_OBJECT (self), 0); + + + self->ok_button = gtk_dialog_add_button (GTK_DIALOG (self), + GTK_STOCK_OK, + GTK_RESPONSE_OK); + gtk_widget_grab_default (self->ok_button); +} + +static void +accel_map_foreach (gpointer data, + const gchar *accel_path, + guint accel_key, + guint accel_mods, + gboolean changed) +{ + EggAccelDialog *self = data; + GtkTreeIter iter; + gchar *accel_name; + + gtk_list_store_append (self->accel_store, &iter); + if (accel_key != 0) + accel_name = gtk_accelerator_name (accel_key, accel_mods); + else + accel_name = ""; + + gtk_list_store_set (self->accel_store, &iter, + 0, accel_path, + 1, accel_name, + -1); + if (accel_key != 0) + g_free(accel_name); +} + +void +egg_accel_dialog_rescan_accels (EggAccelDialog *self) +{ + g_return_if_fail (EGG_IS_ACCEL_DIALOG (self)); + + gtk_list_store_clear (self->accel_store); + gtk_accel_map_foreach (self, accel_map_foreach); +} + +/* make sure the currently selected accel is up to date */ +static void +refresh_selected_row (EggAccelDialog *self) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + + g_return_if_fail (EGG_IS_ACCEL_DIALOG (self)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->accel_view)); + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + char *accel_path; + + /* get the accel path for the selected row */ + gtk_tree_model_get (GTK_TREE_MODEL (self->accel_store), &iter, + 0, &accel_path, -1); + if (accel_path) { + GtkAccelKey key; + + if (gtk_accel_map_lookup_entry (accel_path, &key)) { + char *accel_name; + + accel_name = gtk_accelerator_name (key.accel_key, key.accel_mods); + gtk_list_store_set (self->accel_store, &iter, 1, accel_name, -1); + g_free (accel_name); + } + g_free (accel_path); + } + } +} + +static void +accel_path_selection_changed (GtkTreeSelection *selection, + EggAccelDialog *self) +{ + GtkTreeIter iter; + + /* just make sure the selected row is up to date */ + refresh_selected_row (self); + + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + char *accel_path; + + /* get the accel path for the selected row */ + gtk_tree_model_get (GTK_TREE_MODEL (self->accel_store), &iter, + 0, &accel_path, -1); + if (accel_path) { + GtkAccelKey key; + + if (gtk_accel_map_lookup_entry (accel_path, &key)) { + gchar *keyname; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->shift_toggle), + (key.accel_mods & GDK_SHIFT_MASK)!=0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->ctrl_toggle), + (key.accel_mods & GDK_CONTROL_MASK)!=0); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->alt_toggle), + (key.accel_mods & GDK_MOD1_MASK)!=0); + keyname = gdk_keyval_name (key.accel_key); + if (keyname) + gtk_entry_set_text (GTK_ENTRY (self->key_entry), keyname); + else + gtk_entry_set_text (GTK_ENTRY (self->key_entry), ""); + } + } + g_free (accel_path); + } +} + +static void +accel_path_set (GtkWidget *button, EggAccelDialog *self) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + gboolean changed = FALSE; + + g_return_if_fail (EGG_IS_ACCEL_DIALOG (self)); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->accel_view)); + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + char *accel_path; + + /* get the accel path for the selected row */ + gtk_tree_model_get (GTK_TREE_MODEL (self->accel_store), &iter, + 0, &accel_path, -1); + if (accel_path) { + GdkModifierType accel_mods = 0; + const gchar *key_name; + guint accel_key = 0; + + /* get modifiers */ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(self->shift_toggle))) + accel_mods |= GDK_SHIFT_MASK; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(self->ctrl_toggle))) + accel_mods |= GDK_CONTROL_MASK; + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(self->alt_toggle))) + accel_mods |= GDK_MOD1_MASK; + + key_name = gtk_entry_get_text (GTK_ENTRY (self->key_entry)); + /* check to see if entyr is empty -- if so, unset accel */ + if (key_name[0] != '\0') { + accel_key = gdk_keyval_from_name (key_name); + + if (accel_key) { + changed = gtk_accel_map_change_entry (accel_path, + accel_key, accel_mods, + TRUE); + } + } else + changed = gtk_accel_map_change_entry (accel_path, 0, 0, TRUE); + + g_free (accel_path); + } + } + if (!changed) + gdk_beep (); + accel_path_selection_changed (selection, self); +} + +static void +accel_path_reset (GtkWidget *button, EggAccelDialog *self) +{ + GtkTreeSelection *selection; + GtkTreeIter iter; + gboolean changed = FALSE; + + g_return_if_fail (EGG_IS_ACCEL_DIALOG (self)); + + g_message ("don't know how to reset to defaults :("); + return; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (self->accel_view)); + if (gtk_tree_selection_get_selected (selection, NULL, &iter)) { + char *accel_path; + + /* get the accel path for the selected row */ + gtk_tree_model_get (GTK_TREE_MODEL (self->accel_store), &iter, + 0, &accel_path, -1); + if (accel_path) { + changed = gtk_accel_map_change_entry (accel_path, 0, 0, TRUE); + g_free (accel_path); + } + } + if (!changed) + gdk_beep (); + accel_path_selection_changed (selection, self); +} + +GtkWidget * +egg_accel_dialog_new (void) +{ + return g_object_new(EGG_TYPE_ACCEL_DIALOG, NULL); +} diff --git a/lib/egg/egg-accel-dialog.h b/lib/egg/egg-accel-dialog.h new file mode 100644 index 000000000..8aa2fc435 --- /dev/null +++ b/lib/egg/egg-accel-dialog.h @@ -0,0 +1,43 @@ +#ifndef EGG_ACCEL_DIALOG_H +#define EGG_ACCEL_DIALOG_H + +#include <gtk/gtk.h> + +#define EGG_TYPE_ACCEL_DIALOG (egg_accel_dialog_get_type ()) +#define EGG_ACCEL_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_ACCEL_DIALOG, EggAccelDialog)) +#define EGG_ACCEL_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_ACCEL_DIALOG, EggAccelDialogClass)) +#define EGG_IS_ACCEL_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_ACCEL_DIALOG)) +#define EGG_IS_ACCEL_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_ACCEL_DIALOG)) +#define EGG_ACCEL_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_ACCEL_DIALOG, EggAccelDialogClass)) + +typedef struct _EggAccelDialog EggAccelDialog; +typedef struct _EggAccelDialogClass EggAccelDialogClass; + +struct _EggAccelDialog { + GtkDialog parent; + + GtkListStore *accel_store; + + GtkWidget *accel_view; + + GtkWidget *shift_toggle; + GtkWidget *ctrl_toggle; + GtkWidget *alt_toggle; + GtkWidget *key_entry; + + GtkWidget *set_button; + GtkWidget *reset_button; + + GtkWidget *ok_button; +}; + +struct _EggAccelDialogClass { + GtkDialogClass parent_class; +}; + +GType egg_accel_dialog_get_type (void); +GtkWidget *egg_accel_dialog_new (void); + +void egg_accel_dialog_rescan_accels (EggAccelDialog *accel_dialog); + +#endif diff --git a/lib/egg/egg-action-group.c b/lib/egg/egg-action-group.c new file mode 100644 index 000000000..b1aba64a5 --- /dev/null +++ b/lib/egg/egg-action-group.c @@ -0,0 +1,297 @@ +#include "egg-action-group.h" +#include "egg-toggle-action.h" +#include "egg-radio-action.h" + +#ifndef _ +# define _(s) (s) +#endif + +static void egg_action_group_init (EggActionGroup *self); +static void egg_action_group_class_init (EggActionGroupClass *class); + +GType +egg_action_group_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggActionGroupClass), + (GBaseInitFunc) egg_action_group_init, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_action_group_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (EggActionGroup), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_action_group_init, + }; + + type = g_type_register_static (G_TYPE_OBJECT, "EggActionGroup", + &type_info, 0); + } + + return type; +} + +static GObjectClass *parent_class = NULL; +static void egg_action_group_finalize (GObject *object); +static EggAction *egg_action_group_real_get_action (EggActionGroup *self, + const gchar *name); + +static void +egg_action_group_class_init (EggActionGroupClass *class) +{ + GObjectClass *object_class; + + object_class = G_OBJECT_CLASS (class); + parent_class = g_type_class_peek_parent (class); + + object_class->finalize = egg_action_group_finalize; + class->get_action = egg_action_group_real_get_action; +} + +static void +egg_action_group_init (EggActionGroup *self) +{ + self->name = NULL; + self->actions = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); +} + +/** + * egg_action_group_new: + * @name: the name of the action group + * + * Creates a new EggActionGroup object. + * + * Returns: the new EggActionGroup + */ +EggActionGroup * +egg_action_group_new(const gchar *name) +{ + EggActionGroup *self; + + self = g_object_new (EGG_TYPE_ACTION_GROUP, NULL); + self->name = g_strdup (name); + + return self; +} + +static void +egg_action_group_finalize (GObject *object) +{ + EggActionGroup *self; + + self = EGG_ACTION_GROUP (object); + + g_free (self->name); + self->name = NULL; + + g_hash_table_destroy (self->actions); + self->actions = NULL; + + if (parent_class->finalize) + (* parent_class->finalize) (object); +} + +static EggAction * +egg_action_group_real_get_action (EggActionGroup *self, + const gchar *action_name) +{ + return g_hash_table_lookup (self->actions, action_name); +} + +/** + * egg_action_group_get_name: + * @action_group: the action group + * + * Returns: the name of the EggActionGroup + */ +const gchar * +egg_action_group_get_name (EggActionGroup *action_group) +{ + g_return_val_if_fail (EGG_IS_ACTION_GROUP (action_group), NULL); + + return action_group->name; +} + +/** + * egg_action_group_get_action: + * @action_group: the action group + * @action_name: the name of the action + * + * This function looks up an action in the action group by name. + * + * Returns: the action, or NULL if no action by that name exists + */ +EggAction * +egg_action_group_get_action (EggActionGroup *action_group, + const gchar *action_name) +{ + g_return_val_if_fail (EGG_IS_ACTION_GROUP (action_group), NULL); + g_return_val_if_fail (EGG_ACTION_GROUP_GET_CLASS (action_group)->get_action != NULL, NULL); + + return (* EGG_ACTION_GROUP_GET_CLASS (action_group)->get_action) + (action_group, action_name); +} + +/** + * egg_action_group_add_action: + * @action_group: the action group + * @action: an action + * + * This function adds an action object to the action group. + */ +void +egg_action_group_add_action (EggActionGroup *action_group, + EggAction *action) +{ + g_return_if_fail (EGG_IS_ACTION_GROUP (action_group)); + g_return_if_fail (EGG_IS_ACTION (action)); + g_return_if_fail (action->name != NULL); + + g_hash_table_insert (action_group->actions, g_strdup (action->name), + g_object_ref (action)); +} + +/** + * egg_action_group_removes_action: + * @action_group: the action group + * @action: an action + * + * This function removes an action object to the action group. + */ +void +egg_action_group_remove_action (EggActionGroup *action_group, + EggAction *action) +{ + g_return_if_fail (EGG_IS_ACTION_GROUP (action_group)); + g_return_if_fail (EGG_IS_ACTION (action)); + g_return_if_fail (action->name != NULL); + + /* extra protection to make sure action->name is valid */ + g_object_ref (action); + g_hash_table_remove (action_group->actions, action->name); + g_object_unref (action); +} + +static void +add_single_action (gpointer key, gpointer value, gpointer user_data) +{ + GList **list = user_data; + + *list = g_list_prepend (*list, value); +} + +/** + * egg_action_group_list_actions: + * @action_group: the action group + * + * Lists the actions in the action group. + * + * Returns: an allocated list of the action objects in the action group + */ +GList * +egg_action_group_list_actions (EggActionGroup *action_group) +{ + GList *actions = NULL; + + g_hash_table_foreach (action_group->actions, add_single_action, &actions); + + return g_list_reverse (actions); +} + + +/** + * egg_action_group_add_actions: + * @action_group: the action group + * @entries: an array of action descriptions + * @n_entries: the number of entries + * + * This is a convenience routine to create a number of actions and add + * them to the action group. Each member of the array describes an + * action to create. + */ +void +egg_action_group_add_actions (EggActionGroup *action_group, + EggActionGroupEntry *entries, + guint n_entries) +{ + guint i; + + for (i = 0; i < n_entries; i++) + { + EggAction *action; + GType action_type; + gchar *accel_path; + + switch (entries[i].entry_type) { + case NORMAL_ACTION: + action_type = EGG_TYPE_ACTION; + break; + case TOGGLE_ACTION: + action_type = EGG_TYPE_TOGGLE_ACTION; + break; + case RADIO_ACTION: + action_type = EGG_TYPE_RADIO_ACTION; + break; + default: + g_warning ("unsupported action type"); + action_type = EGG_TYPE_ACTION; + } + + action = g_object_new (action_type, + "name", entries[i].name, + "label", _(entries[i].label), + "tooltip", _(entries[i].tooltip), + "stock_id", entries[i].stock_id, + NULL); + + if (entries[i].entry_type == RADIO_ACTION && + entries[i].extra_data != NULL) + { + EggAction *radio_action; + GSList *group; + + radio_action = + egg_action_group_get_action (EGG_ACTION_GROUP (action_group), + entries[i].extra_data); + if (radio_action) + { + group = egg_radio_action_get_group (EGG_RADIO_ACTION (radio_action)); + egg_radio_action_set_group (EGG_RADIO_ACTION (action), group); + } + else + g_warning (G_STRLOC " could not look up `%s'", entries[i].extra_data); + } + + if (entries[i].callback) + g_signal_connect (action, "activate", + entries[i].callback, entries[i].user_data); + + /* set the accel path for the menu item */ + accel_path = g_strconcat ("<Actions>/", action_group->name, "/", + entries[i].name, NULL); + if (entries[i].accelerator) + { + guint accel_key = 0; + GdkModifierType accel_mods; + + gtk_accelerator_parse (entries[i].accelerator, &accel_key, + &accel_mods); + if (accel_key) + gtk_accel_map_add_entry (accel_path, accel_key, accel_mods); + } + + egg_action_set_accel_path (action, accel_path); + g_free(accel_path); + + egg_action_group_add_action (action_group, action); + g_object_unref (action); + } +} diff --git a/lib/egg/egg-action-group.h b/lib/egg/egg-action-group.h new file mode 100644 index 000000000..2ee05dcec --- /dev/null +++ b/lib/egg/egg-action-group.h @@ -0,0 +1,71 @@ +#ifndef EGG_ACTION_GROUP_H +#define EGG_ACTION_GROUP_H + +#include <gtk/gtk.h> +#include <egg-action.h> + +#define EGG_TYPE_ACTION_GROUP (egg_action_group_get_type ()) +#define EGG_ACTION_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_ACTION_GROUP, EggActionGroup)) +#define EGG_ACTION_GROUP_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), EGG_TYPE_ACTION_GROUP, EggActionGroupClass)) +#define EGG_IS_ACTION_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_ACTION_GROUP)) +#define EGG_IS_ACTION_GROUP_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), EGG_TYPE_ACTION_GROUP)) +#define EGG_ACTION_GROUP_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), EGG_TYPE_ACTION_GROUP, EggActionGroupClass)) + +typedef struct _EggActionGroup EggActionGroup; +typedef struct _EggActionGroupClass EggActionGroupClass; +typedef struct _EggActionGroupEntry EggActionGroupEntry; + +struct _EggActionGroup +{ + GObject parent; + + gchar *name; + GHashTable *actions; +}; + +struct _EggActionGroupClass +{ + GObjectClass parent_class; + + EggAction *(* get_action) (EggActionGroup *action_group, + const gchar *action_name); +}; + +typedef enum { + NORMAL_ACTION, + TOGGLE_ACTION, + RADIO_ACTION +} EggActionGroupEntryType; + +struct _EggActionGroupEntry { + gchar *name; + gchar *label; + gchar *stock_id; + gchar *accelerator; + gchar *tooltip; + + GCallback callback; + gpointer user_data; + + EggActionGroupEntryType entry_type; + gchar *extra_data; +}; + +GType egg_action_group_get_type (void); + +EggActionGroup *egg_action_group_new (const gchar *name); + +const gchar *egg_action_group_get_name (EggActionGroup *action_group); +EggAction *egg_action_group_get_action (EggActionGroup *action_group, + const gchar *action_name); +GList *egg_action_group_list_actions (EggActionGroup *action_group); +void egg_action_group_add_action (EggActionGroup *action_group, + EggAction *action); +void egg_action_group_remove_action (EggActionGroup *action_group, + EggAction *action); + +void egg_action_group_add_actions (EggActionGroup *action_group, + EggActionGroupEntry *entries, + guint n_entries); + +#endif diff --git a/lib/egg/egg-action.c b/lib/egg/egg-action.c new file mode 100644 index 000000000..360ba358e --- /dev/null +++ b/lib/egg/egg-action.c @@ -0,0 +1,961 @@ +#include "egg-action.h" +#include "eggtoolbutton.h" + +#ifndef _ +# define _(s) (s) +#endif + +/* some code for making arbitrary GtkButtons that act like toolbar + * buttons */ +static GtkWidget *tool_button_new (GType button_type, + const gchar *text, + GtkWidget *icon); +static GtkWidget *tool_button_get_label (GtkWidget *button); +static GtkWidget *tool_button_get_icon (GtkWidget *button); + +enum { + ACTIVATE, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_NAME, + PROP_LABEL, + PROP_SHORT_LABEL, + PROP_TOOLTIP, + PROP_STOCK_ID, + PROP_SENSITIVE, + PROP_VISIBLE, +}; + +static void egg_action_init (EggAction *action); +static void egg_action_class_init (EggActionClass *class); + +static GQuark accel_path_id = 0; +static const gchar *accel_path_key = "EggAction::accel_path"; + +GType +egg_action_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (EggAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_action_init, + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EggAction", + &type_info, 0); + } + return type; +} + +static void egg_action_finalize (GObject *object); +static void egg_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void egg_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static GtkWidget *create_menu_item (EggAction *action); +static GtkWidget *create_tool_item (EggAction *action); +static void connect_proxy (EggAction *action, + GtkWidget *proxy); +static void disconnect_proxy (EggAction *action, + GtkWidget *proxy); + +static GObjectClass *parent_class = NULL; +static guint action_signals[LAST_SIGNAL] = { 0 }; + + +static void +egg_action_class_init (EggActionClass *class) +{ + GObjectClass *object_class; + + accel_path_id = g_quark_from_static_string(accel_path_key); + + parent_class = g_type_class_peek_parent (class); + object_class = G_OBJECT_CLASS(class); + + object_class->finalize = egg_action_finalize; + object_class->set_property = egg_action_set_property; + object_class->get_property = egg_action_get_property; + + class->activate = NULL; + + class->create_menu_item = create_menu_item; + class->create_tool_item = create_tool_item; + class->connect_proxy = connect_proxy; + class->disconnect_proxy = disconnect_proxy; + + class->menu_item_type = GTK_TYPE_IMAGE_MENU_ITEM; + class->toolbar_item_type = EGG_TYPE_TOOL_BUTTON; + + g_object_class_install_property (object_class, + PROP_NAME, + g_param_spec_string ("name", + _("Name"), + _("A unique name for the action."), + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (object_class, + PROP_LABEL, + g_param_spec_string ("label", + _("Label"), + _("The label used for menu items and buttons that activate this action."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SHORT_LABEL, + g_param_spec_string ("short_label", + _("Short label"), + _("A shorter label that may be used on toolbar buttons."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_TOOLTIP, + g_param_spec_string ("tooltip", + _("Tooltip"), + _("A tooltip for this action."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_STOCK_ID, + g_param_spec_string ("stock_id", + _("Stock Icon"), + _("The stock icon displayed in widgets representing this action."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_SENSITIVE, + g_param_spec_boolean ("sensitive", + _("Sensitive"), + _("Whether the action is enabled."), + TRUE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + PROP_VISIBLE, + g_param_spec_boolean ("visible", + _("Visible"), + _("Whether the action is visible."), + TRUE, + G_PARAM_READWRITE)); + + action_signals[ACTIVATE] = + g_signal_new ("activate", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EggActionClass, activate), NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + + +static void +egg_action_init (EggAction *action) +{ + action->name = NULL; + action->label = NULL; + action->short_label = NULL; + action->tooltip = NULL; + action->stock_id = NULL; + + action->sensitive = TRUE; + action->visible = TRUE; + + action->label_set = FALSE; + action->short_label_set = FALSE; + + action->accel_quark = 0; + + action->proxies = NULL; +} + +static void +egg_action_finalize (GObject *object) +{ + EggAction *action; + + action = EGG_ACTION (object); + + g_free (action->name); + g_free (action->label); + g_free (action->short_label); + g_free (action->tooltip); + g_free (action->stock_id); +} + +static void +egg_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EggAction *action; + + action = EGG_ACTION (object); + + switch (prop_id) + { + case PROP_NAME: + g_free (action->name); + action->name = g_value_dup_string (value); + break; + case PROP_LABEL: + g_free (action->label); + action->label = g_value_dup_string (value); + action->label_set = (action->label != NULL); + /* if label is unset, then use the label from the stock item */ + if (!action->label_set && action->stock_id) + { + GtkStockItem stock_item; + + if (gtk_stock_lookup(action->stock_id, &stock_item)) + action->label = g_strdup(stock_item.label); + } + /* if short_label is unset, set short_label=label */ + if (!action->short_label_set) + { + g_free(action->short_label); + action->short_label = g_strdup(action->label); + g_object_notify(object, "short_label"); + } + break; + case PROP_SHORT_LABEL: + g_free (action->short_label); + action->short_label = g_value_dup_string (value); + action->short_label_set = (action->short_label != NULL); + /* if short_label is unset, then use the value of label */ + if (!action->short_label_set) + { + action->short_label = g_strdup(action->label); + } + break; + case PROP_TOOLTIP: + g_free (action->tooltip); + action->tooltip = g_value_dup_string (value); + break; + case PROP_STOCK_ID: + g_free (action->stock_id); + action->stock_id = g_value_dup_string (value); + /* update label and short_label if appropriate */ + if (!action->label_set) + { + GtkStockItem stock_item; + + g_free(action->label); + if (gtk_stock_lookup(action->stock_id, &stock_item)) + action->label = g_strdup(stock_item.label); + else + action->label = NULL; + g_object_notify(object, "label"); + } + if (!action->short_label_set) + { + g_free(action->short_label); + action->short_label = g_strdup(action->label); + g_object_notify(object, "short_label"); + } + break; + case PROP_SENSITIVE: + action->sensitive = g_value_get_boolean (value); + break; + case PROP_VISIBLE: + action->visible = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +egg_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EggAction *action; + + action = EGG_ACTION (object); + + switch (prop_id) + { + case PROP_NAME: + g_value_set_string (value, action->name); + break; + case PROP_LABEL: + g_value_set_string (value, action->label); + break; + case PROP_SHORT_LABEL: + g_value_set_string (value, action->short_label); + break; + case PROP_TOOLTIP: + g_value_set_string (value, action->tooltip); + break; + case PROP_STOCK_ID: + g_value_set_string (value, action->stock_id); + break; + case PROP_SENSITIVE: + g_value_set_boolean (value, action->sensitive); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, action->visible); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GtkWidget * +create_menu_item (EggAction *action) +{ + GType menu_item_type; + + menu_item_type = EGG_ACTION_GET_CLASS (action)->menu_item_type; + + return g_object_new (menu_item_type, NULL); +} + +static GtkWidget * +create_tool_item (EggAction *action) +{ + GType toolbar_item_type; + + toolbar_item_type = EGG_ACTION_GET_CLASS (action)->toolbar_item_type; + + return g_object_new (toolbar_item_type, NULL); +} + +static void +egg_action_remove_proxy (GtkWidget *widget, EggAction *action) +{ + action->proxies = g_slist_remove (action->proxies, widget); +} + +static void +egg_action_sync_property (EggAction *action, GParamSpec *pspec, + GtkWidget *proxy) +{ + const gchar *property; + GValue value = { 0, }; + + property = g_param_spec_get_name (pspec); + + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); + g_object_get_property (G_OBJECT (action), property, &value); + + g_object_set_property (G_OBJECT (proxy), property, &value); + g_value_unset (&value); +} + +static void +egg_action_sync_label (EggAction *action, GParamSpec *pspec, GtkWidget *proxy) +{ + GtkWidget *label = NULL; + + g_return_if_fail (GTK_IS_MENU_ITEM (proxy)); + label = GTK_BIN(proxy)->child; + + if (GTK_IS_LABEL (label)) + gtk_label_set_label (GTK_LABEL (label), action->label); +} + +static void +egg_action_sync_short_label (EggAction *action, GParamSpec *pspec, + GtkWidget *proxy) +{ + GValue value = { 0, }; + + g_value_init(&value, G_TYPE_STRING); + g_object_get_property (G_OBJECT (action), "short_label", &value); + + g_object_set_property (G_OBJECT (proxy), "label", &value); + g_value_unset (&value); +} + +static void +egg_action_sync_stock_id (EggAction *action, GParamSpec *pspec, + GtkWidget *proxy) +{ + GtkWidget *image = NULL; + + if (GTK_IS_IMAGE_MENU_ITEM (proxy)) + { + image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy)); + + if (GTK_IS_IMAGE (image)) + gtk_image_set_from_stock (GTK_IMAGE (image), + action->stock_id, GTK_ICON_SIZE_MENU); + } +} + +static GtkWidget * +egg_action_create_menu_proxy (EggToolItem *tool_item, EggAction *action) +{ + return egg_action_create_menu_item (action); +} + +static void +connect_proxy (EggAction *action, GtkWidget *proxy) +{ + g_object_ref (action); + g_object_set_data_full (G_OBJECT (proxy), "egg-action", action, + g_object_unref); + + /* add this widget to the list of proxies */ + action->proxies = g_slist_prepend (action->proxies, proxy); + g_signal_connect (proxy, "destroy", + G_CALLBACK (egg_action_remove_proxy), action); + + g_signal_connect_object (action, "notify::sensitive", + G_CALLBACK (egg_action_sync_property), proxy, 0); + gtk_widget_set_sensitive (proxy, action->sensitive); + + g_signal_connect_object (action, "notify::visible", + G_CALLBACK (egg_action_sync_property), proxy, 0); + if (action->visible) + gtk_widget_show (proxy); + else + gtk_widget_hide (proxy); + + if (GTK_IS_MENU_ITEM (proxy)) + { + GtkWidget *label; + /* menu item specific synchronisers ... */ + + label = GTK_BIN (proxy)->child; + + /* make sure label is a label */ + if (label && !GTK_IS_LABEL (label)) + { + gtk_container_remove (GTK_CONTAINER(proxy), label); + label = NULL; + } + if (!label) + { + label = g_object_new (GTK_TYPE_ACCEL_LABEL, + "use_underline", TRUE, + "xalign", 0.0, + "visible", TRUE, + "parent", proxy, + "accel_widget", proxy, + NULL); + } + gtk_label_set_label (GTK_LABEL (label), action->label); + g_signal_connect_object (action, "notify::label", + G_CALLBACK (egg_action_sync_label), proxy, 0); + + if (GTK_IS_IMAGE_MENU_ITEM (proxy)) + { + GtkWidget *image; + + image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (proxy)); + if (image && !GTK_IS_IMAGE(image)) + { + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy),NULL); + image = NULL; + } + if (!image) + { + image = gtk_image_new_from_stock (NULL, + GTK_ICON_SIZE_MENU); + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (proxy), + image); + gtk_widget_show (image); + } + gtk_image_set_from_stock (GTK_IMAGE (image), + action->stock_id, GTK_ICON_SIZE_MENU); + g_signal_connect_object (action, "notify::stock_id", + G_CALLBACK (egg_action_sync_stock_id), + proxy, 0); + } + + if (action->accel_quark) + { + gtk_menu_item_set_accel_path (GTK_MENU_ITEM (proxy), + g_quark_to_string (action->accel_quark)); + } + + g_signal_connect_object (proxy, "activate", + G_CALLBACK (egg_action_activate), action, + G_CONNECT_SWAPPED); + } + else if (EGG_IS_TOOL_BUTTON (proxy)) + { + GtkWidget *label; + GtkWidget *icon; + /* toolbar button specific synchronisers ... */ + + /* synchronise the label */ + g_object_set (G_OBJECT (proxy), + "label", action->short_label, + "use_underline", TRUE, + NULL); + g_signal_connect_object (action, "notify::short_label", + G_CALLBACK (egg_action_sync_short_label), + proxy, 0); + + g_object_set (G_OBJECT (proxy), "stock_id", action->stock_id, NULL); + g_signal_connect_object (action, "notify::stock_id", + G_CALLBACK (egg_action_sync_property), proxy, 0); + + g_signal_connect_object (proxy, "create_menu_proxy", + G_CALLBACK (egg_action_create_menu_proxy), + action, 0); + + g_signal_connect_object (proxy, "clicked", + G_CALLBACK (egg_action_activate), action, + G_CONNECT_SWAPPED); + } +} + +static void +disconnect_proxy (EggAction *action, GtkWidget *proxy) +{ + static guint notify_id = 0; + + if (!notify_id) + notify_id = g_signal_lookup ("notify", G_TYPE_OBJECT); + + g_object_set_data (G_OBJECT (proxy), "egg-action", NULL); + + /* remove proxy from list of proxies */ + g_signal_handlers_disconnect_by_func (proxy, + G_CALLBACK (egg_action_remove_proxy), + action); + egg_action_remove_proxy (proxy, action); + + /* disconnect the activate handler */ + g_signal_handlers_disconnect_by_func (proxy, + G_CALLBACK (egg_action_activate), + action); + + /* disconnect handlers for notify::* signals */ + g_signal_handlers_disconnect_by_func (proxy, + G_CALLBACK (egg_action_sync_property), + action); + + g_signal_handlers_disconnect_by_func (action, + G_CALLBACK (egg_action_sync_stock_id), proxy); + + /* menu item specific synchronisers ... */ + g_signal_handlers_disconnect_by_func (action, + G_CALLBACK (egg_action_sync_label), + proxy); + + gtk_menu_item_set_accel_path (GTK_MENU_ITEM (proxy), NULL); + + /* toolbar button specific synchronisers ... */ + g_signal_handlers_disconnect_by_func (action, + G_CALLBACK (egg_action_sync_short_label), + proxy); + g_signal_handlers_disconnect_by_func (proxy, + G_CALLBACK (egg_action_create_menu_proxy), + action); +} + +/** + * egg_action_activate: + * @action: the action object + * + * Calling this function will emit the "activate" signal on the + * specified action. It gets called by the proxy widgets when they + * get activated. + * + * It can also be used to manually activate an action. + */ +void +egg_action_activate (EggAction *action) +{ + g_signal_emit (action, action_signals[ACTIVATE], 0); +} + +/** + * egg_action_create_icon: + * @action: the action object + * @icon_size: the size of the icon that should be created. + * + * This function is intended for use by action implementations to + * create icons displayed in the proxy widgets. + * + * Returns: a widget that displays the icon for this action. + */ +GtkWidget * +egg_action_create_icon (EggAction *action, GtkIconSize icon_size) +{ + if (action->stock_id) + return gtk_image_new_from_stock (action->stock_id, icon_size); + else + return NULL; +} + +/** + * egg_action_create_menu_item: + * @action: the action object + * + * This function creates a menu item widget that proxies for the given + * action. + * + * Returns: a menu item connected to the action. + */ +GtkWidget * +egg_action_create_menu_item (EggAction *action) +{ + GtkWidget *menu_item; + + menu_item = (* EGG_ACTION_GET_CLASS (action)->create_menu_item) (action); + + (* EGG_ACTION_GET_CLASS (action)->connect_proxy) (action, menu_item); + + return menu_item; +} + +/** + * egg_action_create_tool_item: + * @action: the action object + * + * This function creates a toolbar item widget that proxies for the + * given action. + * + * Returns: a toolbar item connected to the action. + */ +GtkWidget * +egg_action_create_tool_item (EggAction *action) +{ + GtkWidget *button; + + button = (* EGG_ACTION_GET_CLASS (action)->create_tool_item) (action); + + (* EGG_ACTION_GET_CLASS (action)->connect_proxy) (action, button); + + return button; +} + +/** + * egg_action_connect_proxy: + * @action: the action object + * @proxy: the proxy widget + * + * This function connects a widget to an action object as a proxy. It + * will synchronise various properties of the action with the widget + * (such as label text, icon, tooltip, etc), and attaches a callback + * so that the action gets activated when the proxy widget does. + * + * If the widget is already connected to an action, it is disconnected + * first. + */ +void +egg_action_connect_proxy (EggAction *action, + GtkWidget *proxy) +{ + EggAction *prev_action; + + g_return_if_fail (EGG_IS_ACTION (action)); + g_return_if_fail (GTK_IS_WIDGET (proxy)); + + prev_action = g_object_get_data (G_OBJECT (proxy), "egg-action"); + + if (prev_action) + { + (* EGG_ACTION_GET_CLASS (action)->disconnect_proxy) (action, proxy); + } + + (* EGG_ACTION_GET_CLASS (action)->connect_proxy) (action, proxy); +} + +/** + * egg_action_disconnect_proxy: + * @action: the action object + * @proxy: the proxy widget + * + * This disconnects a proxy widget from an action. It does not + * destroy the widget, however. + */ +void +egg_action_disconnect_proxy (EggAction *action, + GtkWidget *proxy) +{ + EggAction *prev_action; + + g_return_if_fail (EGG_IS_ACTION (action)); + g_return_if_fail (GTK_IS_WIDGET (proxy)); + + g_return_if_fail (g_object_get_data (G_OBJECT (proxy), "egg-action") != action); + + (* EGG_ACTION_GET_CLASS (action)->disconnect_proxy) (action, proxy); +} + +/** + * egg_action_block_activate_from: + * @action: the action object + * @proxy: a proxy widget + * + * Calling this function disables calls to the egg_action_activate() + * function by signals on the given proxy widget. This is used to + * break notification loops for things like check or radio actions. + * + * This function is intended for use by action implementations. + */ +void +egg_action_block_activate_from (EggAction *action, GtkWidget *proxy) +{ + g_return_if_fail (EGG_IS_ACTION (action)); + + g_signal_handlers_block_by_func (proxy, G_CALLBACK (egg_action_activate), + action); +} + +/** + * egg_action_unblock_activate_from: + * @action: the action object + * @proxy: a proxy widget + * + * Calling this function re-enables calls to the egg_action_activate() + * function by signals on the given proxy widget. This undoes the + * blocking done by egg_action_block_activate_from(). + * + * This function is intended for use by action implementations. + */ +void +egg_action_unblock_activate_from (EggAction *action, GtkWidget *proxy) +{ + g_return_if_fail (EGG_IS_ACTION (action)); + + g_signal_handlers_unblock_by_func (proxy, G_CALLBACK (egg_action_activate), + action); +} + +/** + * egg_action_set_accel_path: + * @action: the action object + * @accel_path: the accelerator path + * + * Sets the accel path for this action. All proxy widgets associated + * with the action will have this accel path, so that their + * accelerators are consistent. + */ +void +egg_action_set_accel_path (EggAction *action, const gchar *accel_path) +{ + action->accel_quark = g_quark_from_string(accel_path); +} + +/* ---- code to create sort-of-toolbar-buttons ---- */ + +static GtkWidget * +tool_button_get_label (GtkWidget *button) +{ + g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); + + return g_object_get_data (G_OBJECT (button), "tool-button-label"); +} + +static GtkWidget * +tool_button_get_icon (GtkWidget *button) +{ + g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); + + return g_object_get_data (G_OBJECT (button), "tool-button-icon"); +} + +static void +tool_button_parent_set (GtkWidget *button, GtkWidget *old_parent) +{ + GtkWidget *box; + GtkWidget *label; + GtkWidget *icon; + + box = g_object_get_data (G_OBJECT (button), "tool-button-box"); + label = g_object_get_data (G_OBJECT (button), "tool-button-label"); + icon = g_object_get_data (G_OBJECT (button), "tool-button-icon"); + + if (button->parent && GTK_IS_TOOLBAR (button->parent)) + { + GtkReliefStyle relief = GTK_RELIEF_NORMAL; + GList *tmp; + + /* set button relief to match toolbar */ + gtk_widget_style_get (GTK_WIDGET (button->parent), + "button_relief", &relief, NULL); + gtk_button_set_relief (GTK_BUTTON (button), relief); + + /* set the button style */ + switch (gtk_toolbar_get_style (GTK_TOOLBAR (button->parent))) + { + case GTK_TOOLBAR_ICONS: + if (icon && !GTK_WIDGET_VISIBLE (icon)) + gtk_widget_show (icon); + if (label && GTK_WIDGET_VISIBLE (label)) + gtk_widget_hide (label); + break; + + case GTK_TOOLBAR_TEXT: + if (icon && GTK_WIDGET_VISIBLE (icon)) + gtk_widget_hide (icon); + if (label && !GTK_WIDGET_VISIBLE (label)) + gtk_widget_show (label); + break; + + case GTK_TOOLBAR_BOTH: + if (icon && !GTK_WIDGET_VISIBLE (icon)) + gtk_widget_show (icon); + if (label && !GTK_WIDGET_VISIBLE (label)) + gtk_widget_show (label); + + if (GTK_IS_HBOX (box)) + { + if (icon) + { + g_object_ref (icon); + gtk_container_remove (GTK_CONTAINER (box), icon); + } + if (label) + { + g_object_ref (label); + gtk_container_remove (GTK_CONTAINER (box), label); + } + gtk_container_remove (GTK_CONTAINER (button), box); + box = gtk_vbox_new (FALSE, 0); + + gtk_widget_show (box); + + if (label) + { + gtk_box_pack_end (GTK_BOX (box), label, FALSE, FALSE, 0); + g_object_unref (label); + } + if (icon) + { + gtk_box_pack_end (GTK_BOX (box), icon, FALSE, FALSE, 0); + g_object_unref (label); + } + gtk_container_add (GTK_CONTAINER (button), box); + g_object_set_data (G_OBJECT (button), "tool-button-box", box); + } + break; + + case GTK_TOOLBAR_BOTH_HORIZ: + if (icon && !GTK_WIDGET_VISIBLE (icon)) + gtk_widget_show (icon); + if (label && !GTK_WIDGET_VISIBLE (label)) + gtk_widget_show (label); + + if (GTK_IS_VBOX (box)) + { + if (icon) + { + g_object_ref (icon); + gtk_container_remove (GTK_CONTAINER (box), icon); + } + if (label) + { + g_object_ref (label); + gtk_container_remove (GTK_CONTAINER (box), label); + } + gtk_container_remove (GTK_CONTAINER (button), box); + box = gtk_hbox_new (FALSE, 0); + + gtk_widget_show (box); + + if (label) + { + gtk_box_pack_end (GTK_BOX (box), label, FALSE, FALSE, 0); + g_object_unref (label); + } + if (icon) + { + gtk_box_pack_end (GTK_BOX (box), icon, FALSE, FALSE, 0); + g_object_unref (label); + } + gtk_container_add (GTK_CONTAINER (button), box); + g_object_set_data (G_OBJECT (button), "tool-button-box", box); + } + break; + } + + /* set the icon size */ + icon = tool_button_get_icon (button); + if (GTK_IS_IMAGE (icon) && + gtk_image_get_storage_type (GTK_IMAGE (icon)) == GTK_IMAGE_STOCK) + { + gchar *stock_id; + + gtk_image_get_stock (GTK_IMAGE (icon), &stock_id, NULL); + stock_id = g_strdup (stock_id); + gtk_image_set_from_stock (GTK_IMAGE (icon), stock_id, + GTK_TOOLBAR (button->parent)->icon_size); + g_free (stock_id); + } + + /* gross hack!!! */ + for (tmp = GTK_TOOLBAR (button->parent)->children; tmp; tmp = tmp->next) + { + GtkToolbarChild *tool_child = tmp->data; + + if (tool_child->widget == button) + { + tool_child->type = GTK_TOOLBAR_CHILD_BUTTON; + tool_child->icon = icon; + tool_child->label = label; + break; + } + } + } +} + +static GtkWidget * +tool_button_new (GType button_type, const gchar *text, GtkWidget *icon) +{ + GtkWidget *button; + GtkWidget *vbox; + GtkWidget *label; + + g_return_val_if_fail (g_type_is_a (button_type, GTK_TYPE_BUTTON), NULL); + + button = g_object_new (button_type, NULL); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (button), vbox); + gtk_widget_show (vbox); + + label = gtk_label_new (text); + gtk_label_set_use_underline (GTK_LABEL (label), TRUE); + gtk_label_set_mnemonic_widget (GTK_LABEL (label), button); + gtk_box_pack_end (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + if (!icon) + icon = gtk_image_new(); + gtk_box_pack_end (GTK_BOX (vbox), icon, FALSE, FALSE, 0); + + g_object_set_data (G_OBJECT (button), "tool-button-box", vbox); + g_object_set_data (G_OBJECT (button), "tool-button-label", label); + g_object_set_data (G_OBJECT (button), "tool-button-icon", icon); + + g_signal_connect (button, "parent_set", + G_CALLBACK (tool_button_parent_set), NULL); + + GTK_WIDGET_UNSET_FLAGS (button, GTK_CAN_FOCUS); + + return button; +} diff --git a/lib/egg/egg-action.h b/lib/egg/egg-action.h new file mode 100644 index 000000000..7acf59210 --- /dev/null +++ b/lib/egg/egg-action.h @@ -0,0 +1,81 @@ +#ifndef EGG_ACTION_H +#define EGG_ACTION_H + +#include <gtk/gtk.h> + +#define EGG_TYPE_ACTION (egg_action_get_type ()) +#define EGG_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_ACTION, EggAction)) +#define EGG_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_ACTION, EggActionClass)) +#define EGG_IS_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_ACTION)) +#define EGG_IS_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_ACTION)) +#define EGG_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_ACTION, EggActionClass)) + +typedef struct _EggAction EggAction; +typedef struct _EggActionClass EggActionClass; + +struct _EggAction +{ + GObject object; + + gchar *name; + gchar *label; + gchar *short_label; + gchar *tooltip; + gchar *stock_id; /* icon */ + + guint sensitive : 1; + guint visible : 1; + guint label_set : 1; /* these two used so we can set label */ + guint short_label_set : 1; /* based on stock id */ + + /* accelerator */ + GQuark accel_quark; + + /* list of proxy widgets */ + GSList *proxies; +}; + +struct _EggActionClass +{ + GObjectClass parent_class; + + /* activation signal */ + void (* activate) (EggAction *action); + + GType menu_item_type; + GType toolbar_item_type; + + /* widget creation routines (not signals) */ + GtkWidget *(* create_menu_item) (EggAction *action); + GtkWidget *(* create_tool_item) (EggAction *action); + void (* connect_proxy) (EggAction *action, + GtkWidget *proxy); + void (* disconnect_proxy) (EggAction *action, + GtkWidget *proxy); +}; + +GType egg_action_get_type (void); + +void egg_action_activate (EggAction *action); + +GtkWidget *egg_action_create_icon (EggAction *action, + GtkIconSize icon_size); +GtkWidget *egg_action_create_menu_item (EggAction *action); +GtkWidget *egg_action_create_tool_item (EggAction *action); +void egg_action_connect_proxy (EggAction *action, + GtkWidget *proxy); +void egg_action_disconnect_proxy (EggAction *action, + GtkWidget *proxy); + +/* protected ... for use by child actions */ +void egg_action_block_activate_from (EggAction *action, + GtkWidget *proxy); +void egg_action_unblock_activate_from (EggAction *action, + GtkWidget *proxy); + +/* protected ... for use by action groups */ +void egg_action_set_accel_path (EggAction *action, + const gchar *accel_path); + + +#endif diff --git a/lib/egg/egg-markup.c b/lib/egg/egg-markup.c new file mode 100644 index 000000000..feae85a00 --- /dev/null +++ b/lib/egg/egg-markup.c @@ -0,0 +1,438 @@ +#include <string.h> +#include "egg-markup.h" +#include "eggtoolbar.h" + +#ifndef _ +# define _(String) (String) +# define N_(String) (String) +#endif + +typedef enum { + STATE_START, + STATE_ROOT, + STATE_MENU, + STATE_TOOLBAR, + STATE_POPUPS, + STATE_ITEM, + STATE_END +} ParseState; + +typedef struct _ParseContext ParseContext; +struct _ParseContext +{ + /* parser state information */ + ParseState state; + ParseState prev_state; + + /* function to call when we finish off a toplevel widget */ + EggWidgetFunc widget_func; + gpointer user_data; + + /* GdkAccelGroup to use for menus */ + GtkAccelGroup *accel_group; + + /* info about the widget we are constructing at the moment */ + GtkWidget *top; + gchar *type; + gchar *name; + + /* the current container we are working on */ + GtkWidget *current; + + /* the ActionGroup used to create menu items */ + EggActionGroup *action_group; +}; + +static void +start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + gboolean raise_error = TRUE; + gchar *error_attr = NULL; + + switch (element_name[0]) + { + case 'R': + if (ctx->state == STATE_START && !strcmp(element_name, "Root")) + { + ctx->state = STATE_ROOT; + raise_error = FALSE; + } + break; + case 'm': + if (ctx->state == STATE_ROOT && !strcmp(element_name, "menu")) + { + ctx->state = STATE_MENU; + + ctx->top = ctx->current = gtk_menu_bar_new(); + ctx->type = "menu"; + ctx->name = NULL; + + raise_error = FALSE; + } + else if (ctx->state == STATE_MENU && !strcmp(element_name, "menuitem")) + { + gint i; + const gchar *action_name = NULL; + EggAction *action = NULL; + + ctx->state = STATE_ITEM; + + for (i = 0; attribute_names[i] != NULL; i++) + { + if (!strcmp(attribute_names[i], "verb")) + { + action_name = attribute_values[i]; + action = egg_action_group_get_action(ctx->action_group, + action_name); + } + } + + if (action) + { + GtkWidget *widget = egg_action_create_menu_item(action); + + gtk_container_add(GTK_CONTAINER(ctx->current), widget); + gtk_widget_show(widget); + } + else + { + g_warning("could not find action '%s'", + action_name ? action_name : "(null)"); + } + + raise_error = FALSE; + } + break; + case 'd': + if (ctx->state == STATE_ROOT && !strcmp(element_name, "dockitem")) + { + gint i; + + ctx->state = STATE_TOOLBAR; + + ctx->top = ctx->current = egg_toolbar_new(); + ctx->type = "toolbar"; + for (i = 0; attribute_names[i] != NULL; i++) + { + if (!strcmp(attribute_names[i], "name")) + ctx->name = g_strdup(attribute_values[i]); + } + + raise_error = FALSE; + } + break; + case 'p': + if (ctx->state == STATE_ROOT && !strcmp(element_name, "popups")) + { + ctx->state = STATE_POPUPS; + raise_error = FALSE; + } + else if (ctx->state == STATE_POPUPS &&!strcmp(element_name, "popup")) + { + gint i; + + ctx->state = STATE_MENU; + + ctx->top = ctx->current = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(ctx->current), ctx->accel_group); + ctx->type = "popup"; + for (i = 0; attribute_names[i] != NULL; i++) + { + if (!strcmp(attribute_names[i], "name")) + { + ctx->name = g_strdup(attribute_values[i]); + gtk_menu_set_title(GTK_MENU(ctx->current), ctx->name); + } + else if (!strcmp(attribute_names[i], "tearoff")) + { + GtkWidget *tearoff = gtk_tearoff_menu_item_new(); + + gtk_container_add(GTK_CONTAINER(ctx->current), tearoff); + gtk_widget_show(tearoff); + } + } + + raise_error = FALSE; + } + break; + case 's': + if (ctx->state == STATE_MENU && !strcmp(element_name, "submenu")) + { + gint i; + const gchar *label = NULL; + gboolean tearoff = FALSE; + GtkWidget *widget; + + ctx->state = STATE_MENU; + for (i = 0; attribute_names[i] != NULL; i++) + { + if (!strcmp(attribute_names[i], "label")) + label = g_strdup(attribute_values[i]); + else if (!strcmp(attribute_names[i], "tearoff")) + tearoff = TRUE; + } + widget = gtk_menu_item_new_with_label(label); + gtk_label_set_use_underline(GTK_LABEL(GTK_BIN(widget)->child), TRUE); + gtk_container_add(GTK_CONTAINER(ctx->current), widget); + gtk_widget_show(widget); + + ctx->current = gtk_menu_new(); + gtk_menu_set_accel_group(GTK_MENU(ctx->current), ctx->accel_group); + gtk_menu_set_title(GTK_MENU(ctx->current), label); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(widget), ctx->current); + + if (tearoff) + { + GtkWidget *tearoff = gtk_tearoff_menu_item_new(); + + gtk_container_add(GTK_CONTAINER(ctx->current), tearoff); + gtk_widget_show(tearoff); + } + + raise_error = FALSE; + } + else if ((ctx->state == STATE_MENU || ctx->state == STATE_TOOLBAR) && + !strcmp(element_name, "separator")) + { + ctx->state = STATE_ITEM; + + if (GTK_IS_MENU_SHELL(ctx->current)) + { + GtkWidget *widget = gtk_separator_menu_item_new(); + gtk_container_add(GTK_CONTAINER(ctx->current), widget); + gtk_widget_show(widget); + } + else /* toolbar */ + { + EggToolItem *item = egg_tool_item_new (); + egg_toolbar_insert_tool_item (EGG_TOOLBAR(ctx->current), item, -1); + gtk_widget_show (GTK_WIDGET (item)); + } + + raise_error = FALSE; + } + break; + case 't': + if (ctx->state == STATE_TOOLBAR && !strcmp(element_name, "toolitem")) + { + gint i; + const gchar *action_name = NULL; + EggAction *action = NULL; + + ctx->state = STATE_ITEM; + + for (i = 0; attribute_names[i] != NULL; i++) + { + if (!strcmp(attribute_names[i], "verb")) + { + action_name = attribute_values[i]; + action = egg_action_group_get_action(ctx->action_group, + action_name); + } + } + + if (action) + { + GtkWidget *widget = egg_action_create_tool_item (action); + + gtk_container_add (GTK_CONTAINER (ctx->current), widget); + } + else + { + g_warning("could not find action '%s'", + action_name ? action_name : "(null)"); + } + + raise_error = FALSE; + } + break; + }; + + if (raise_error) + { + gint line_number, char_number; + + g_markup_parse_context_get_position (context, + &line_number, &char_number); + + if (error_attr) + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, + _("Unknown attribute '%s' on line %d char %d"), + error_attr, + line_number, char_number); + else + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ELEMENT, + _("Unknown tag '%s' on line %d char %d"), + element_name, + line_number, char_number); + } +} + +static void +end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + GtkWidget *widget; + + switch (ctx->state) + { + case STATE_START: + g_warning("shouldn't get any end tags at this point"); + /* should do a GError here */ + break; + case STATE_ROOT: + ctx->state = STATE_END; + break; + case STATE_MENU: + widget = GTK_IS_MENU(ctx->current) ? + gtk_menu_get_attach_widget(GTK_MENU(ctx->current)) : NULL; + if (widget) /* not back to the toplevel ... */ + { + ctx->current = widget->parent; + ctx->state = STATE_MENU; + } + else + { + if (GTK_IS_MENU(ctx->current)) /* must be a popup */ + ctx->state = STATE_POPUPS; + else + ctx->state = STATE_ROOT; + + /* notify */ + (* ctx->widget_func)(ctx->top, ctx->type, ctx->name, ctx->user_data); + ctx->top = NULL; + ctx->type = NULL; + g_free(ctx->name); + ctx->name = NULL; + ctx->current = NULL; + } + break; + case STATE_TOOLBAR: + ctx->state = STATE_ROOT; + + /* notify */ + (* ctx->widget_func)(ctx->top, ctx->type, ctx->name, ctx->user_data); + ctx->top = NULL; + ctx->type = NULL; + g_free(ctx->name); + ctx->name = NULL; + ctx->current = NULL; + break; + case STATE_POPUPS: + ctx->state = STATE_ROOT; + break; + case STATE_ITEM: + if (GTK_IS_MENU_SHELL(ctx->current)) + ctx->state = STATE_MENU; + else + ctx->state = STATE_TOOLBAR; + break; + case STATE_END: + g_warning("shouldn't get any end tags at this point"); + /* should do a GError here */ + break; + } +} + +static void +cleanup (GMarkupParseContext *context, + GError *error, + gpointer user_data) +{ + ParseContext *ctx = user_data; + + gtk_widget_destroy(ctx->top); + ctx->top = NULL; + ctx->type = NULL; + g_free(ctx->name); + ctx->name = NULL; + ctx->current = NULL; +} + + +static GMarkupParser ui_parser = { + start_element_handler, + end_element_handler, + NULL, + NULL, + cleanup +}; + + +gboolean +egg_create_from_string (EggActionGroup *action_group, + EggWidgetFunc widget_func, gpointer user_data, + GtkAccelGroup *accel_group, + const gchar *buffer, guint length, + GError **error) +{ + ParseContext ctx = { 0 }; + GMarkupParseContext *context; + gboolean res = TRUE; + + g_return_val_if_fail(EGG_IS_ACTION_GROUP(action_group), FALSE); + g_return_val_if_fail(widget_func != NULL, FALSE); + g_return_val_if_fail(GTK_IS_ACCEL_GROUP(accel_group), FALSE); + g_return_val_if_fail(buffer != NULL, FALSE); + + ctx.state = STATE_START; + ctx.widget_func = widget_func; + ctx.user_data = user_data; + ctx.accel_group = accel_group; + ctx.top = NULL; + ctx.type = NULL; + ctx.name = NULL; + ctx.current = NULL; + ctx.action_group = action_group; + + context = g_markup_parse_context_new(&ui_parser, 0, &ctx, NULL); + if (length < 0) + length = strlen(buffer); + + if (g_markup_parse_context_parse(context, buffer, length, error)) + { + if (!g_markup_parse_context_end_parse(context, error)) + res = FALSE; + } + else + res = FALSE; + + g_markup_parse_context_free (context); + + return res; +} + +gboolean +egg_create_from_file (EggActionGroup *action_group, + EggWidgetFunc widget_func, + gpointer user_data, + GtkAccelGroup *accel_group, + const gchar *filename, + GError **error) +{ + gchar *buffer; + gint length; + gboolean res; + + if (!g_file_get_contents (filename, &buffer, &length, error)) + return FALSE; + + res = egg_create_from_string(action_group, widget_func, user_data, + accel_group, buffer, length, error); + g_free(buffer); + + return res; +} diff --git a/lib/egg/egg-markup.h b/lib/egg/egg-markup.h new file mode 100644 index 000000000..15524189f --- /dev/null +++ b/lib/egg/egg-markup.h @@ -0,0 +1,30 @@ +#ifndef EGG_MARKUP_H +#define EGG_MARKUP_H + +#include <gtk/gtk.h> +#include <egg-action.h> +#include <egg-action-group.h> + + +/* this stuff can go away once I am finished with the merge code */ + +typedef void (*EggWidgetFunc) (GtkWidget *widget, + const gchar *type, + const gchar *name, + gpointer user_data); + +gboolean egg_create_from_string (EggActionGroup *action_group, + EggWidgetFunc widget_func, + gpointer user_data, + GtkAccelGroup *accel_group, + const gchar *buffer, guint length, + GError **error); + +gboolean egg_create_from_file (EggActionGroup *action_group, + EggWidgetFunc widget_func, + gpointer user_data, + GtkAccelGroup *accel_group, + const gchar *filename, + GError **error); + +#endif diff --git a/lib/egg/egg-menu-merge.c b/lib/egg/egg-menu-merge.c new file mode 100644 index 000000000..17895ca99 --- /dev/null +++ b/lib/egg/egg-menu-merge.c @@ -0,0 +1,1316 @@ +#include <string.h> +#include "egg-menu-merge.h" +#include "eggtoolbar.h" +#include "eggseparatortoolitem.h" + +#ifndef _ +# define _(string) (string) +#endif + +#define NODE_INFO(node) ((EggMenuMergeNode *)node->data) + +typedef struct { + guint merge_id; + GQuark action_quark; +} NodeUIReference; + +static void egg_menu_merge_class_init (EggMenuMergeClass *class); +static void egg_menu_merge_init (EggMenuMerge *merge); + +static void egg_menu_merge_queue_update (EggMenuMerge *self); +static void egg_menu_merge_dirty_all (EggMenuMerge *self); + +static GNode *get_child_node (EggMenuMerge *self, GNode *parent, + const gchar *childname, + gint childname_length, + EggMenuMergeNodeType node_type, + gboolean create, gboolean top); +static GNode *egg_menu_merge_get_node (EggMenuMerge *self, + const gchar *path, + EggMenuMergeNodeType node_type, + gboolean create); +static guint egg_menu_merge_next_merge_id (EggMenuMerge *self); + +static void egg_menu_merge_node_prepend_ui_reference (EggMenuMergeNode *node, + guint merge_id, + GQuark action_quark); +static void egg_menu_merge_node_remove_ui_reference (EggMenuMergeNode *node, + guint merge_id); + +enum { + ADD_WIDGET, + REMOVE_WIDGET, + LAST_SIGNAL +}; + +static guint merge_signals[LAST_SIGNAL] = { 0 }; + +static GMemChunk *merge_node_chunk = NULL; + +GType +egg_menu_merge_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggMenuMergeClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_menu_merge_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (EggMenuMerge), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_menu_merge_init, + }; + + type = g_type_register_static (G_TYPE_OBJECT, + "EggMenuMerge", + &type_info, 0); + } + return type; +} + +static void +egg_menu_merge_class_init (EggMenuMergeClass *class) +{ + if (!merge_node_chunk) + merge_node_chunk = g_mem_chunk_create(EggMenuMergeNode, 64, + G_ALLOC_AND_FREE); + + merge_signals[ADD_WIDGET] = + g_signal_new ("add_widget", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EggMenuMergeClass, add_widget), NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + merge_signals[REMOVE_WIDGET] = + g_signal_new ("remove_widget", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE, + G_STRUCT_OFFSET (EggMenuMergeClass, remove_widget), NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + GTK_TYPE_WIDGET); + +} + + +static void +egg_menu_merge_init (EggMenuMerge *self) +{ + guint merge_id; + GNode *node; + + self->accel_group = gtk_accel_group_new(); + + self->root_node = NULL; + self->action_groups = NULL; + + self->last_merge_id = 0; + + + merge_id = egg_menu_merge_next_merge_id(self); + node = get_child_node(self, NULL, "Root", 4, + EGG_MENU_MERGE_ROOT, TRUE, FALSE); + egg_menu_merge_node_prepend_ui_reference(NODE_INFO(node), merge_id, 0); + node = get_child_node(self, self->root_node, "popups", 6, + EGG_MENU_MERGE_POPUPS, TRUE, FALSE); + egg_menu_merge_node_prepend_ui_reference(NODE_INFO(node), merge_id, 0); +} + +EggMenuMerge * +egg_menu_merge_new (void) +{ + return g_object_new(EGG_TYPE_MENU_MERGE, NULL); +} + +void +egg_menu_merge_insert_action_group (EggMenuMerge *self, + EggActionGroup *action_group, gint pos) +{ + g_return_if_fail (EGG_IS_MENU_MERGE(self)); + g_return_if_fail (EGG_IS_ACTION_GROUP(action_group)); + g_return_if_fail (g_list_find(self->action_groups, action_group) == NULL); + + g_object_ref(action_group); + self->action_groups = g_list_insert(self->action_groups, action_group, pos); + + /* dirty all nodes, as action bindings may change */ + egg_menu_merge_dirty_all(self); +} + +void +egg_menu_merge_remove_action_group (EggMenuMerge *self, + EggActionGroup *action_group) +{ + g_return_if_fail (EGG_IS_MENU_MERGE(self)); + g_return_if_fail (EGG_IS_ACTION_GROUP(action_group)); + g_return_if_fail (g_list_find(self->action_groups, action_group) != NULL); + + self->action_groups = g_list_remove(self->action_groups, action_group); + g_object_unref(action_group); + + /* dirty all nodes, as action bindings may change */ + egg_menu_merge_dirty_all(self); +} + +GtkWidget * +egg_menu_merge_get_widget (EggMenuMerge *self, const gchar *path) +{ + GNode *node; + + /* ensure that there are no pending updates before we get the + * widget */ + egg_menu_merge_ensure_update(self); + + node = egg_menu_merge_get_node(self, path, EGG_MENU_MERGE_UNDECIDED, FALSE); + return NODE_INFO(node)->proxy; +} + +static GNode * +get_child_node(EggMenuMerge *self, GNode *parent, + const gchar *childname, gint childname_length, + EggMenuMergeNodeType node_type, + gboolean create, gboolean top) +{ + GNode *child = NULL; + + g_return_val_if_fail(parent == NULL || + (NODE_INFO(parent)->type != EGG_MENU_MERGE_MENUITEM && + NODE_INFO(parent)->type != EGG_MENU_MERGE_TOOLITEM), NULL); + + if (parent) + { + if (childname) + { + for (child = parent->children; child != NULL; child = child->next) + { + if (strlen(NODE_INFO(child)->name) == childname_length && + !strncmp(NODE_INFO(child)->name, childname, childname_length)) + { + /* if undecided about node type, set it */ + if (NODE_INFO(child)->type == EGG_MENU_MERGE_UNDECIDED) + NODE_INFO(child)->type = node_type; + + /* warn about type mismatch */ + if (NODE_INFO(child)->type != EGG_MENU_MERGE_UNDECIDED && + NODE_INFO(child)->type != node_type) + g_warning("node type doesn't match %d (%s is type %d)", + node_type, NODE_INFO(child)->name, + NODE_INFO(child)->type); + + return child; + } + } + } + if (!child && create) + { + EggMenuMergeNode *mnode; + + mnode = g_chunk_new0(EggMenuMergeNode, merge_node_chunk); + mnode->type = node_type; + mnode->name = g_strndup(childname, childname_length); + mnode->dirty = TRUE; + + if (top) + child = g_node_prepend_data(parent, mnode); + else + child = g_node_append_data(parent, mnode); + } + } + else + { + /* handle root node */ + if (self->root_node) + { + child = self->root_node; + if (strncmp(NODE_INFO(child)->name, childname, childname_length) !=0) + g_warning("root node name '%s' doesn't match '%s'", + childname, NODE_INFO(child)->name); + if (NODE_INFO(child)->type != EGG_MENU_MERGE_ROOT) + g_warning("base element must be of type ROOT"); + } + else if (create) + { + EggMenuMergeNode *mnode; + + mnode = g_chunk_new0(EggMenuMergeNode, merge_node_chunk); + mnode->type = node_type; + mnode->name = g_strndup(childname, childname_length); + mnode->dirty = TRUE; + + child = self->root_node = g_node_new(mnode); + } + } + + return child; +} + +static GNode * +egg_menu_merge_get_node(EggMenuMerge *self, const gchar *path, + EggMenuMergeNodeType node_type, gboolean create) +{ + const gchar *pos, *end; + GNode *parent, *node; + + end = path + strlen(path); + pos = path; + parent = node = NULL; + while (pos < end) + { + const gchar *slash; + gsize length; + + slash = strchr(pos, '/'); + if (slash) + length = slash - pos; + else + length = strlen(pos); + + node = get_child_node(self, parent, pos, length, EGG_MENU_MERGE_UNDECIDED, + create, FALSE); + if (!node) + return NULL; + + pos += length + 1; /* move past the node name and the slash too */ + parent = node; + } + + if (NODE_INFO(node)->type == EGG_MENU_MERGE_UNDECIDED) + NODE_INFO(node)->type = node_type; + return node; +} + +static guint +egg_menu_merge_next_merge_id (EggMenuMerge *self) +{ + self->last_merge_id++; + + return self->last_merge_id; +} + +static void +egg_menu_merge_node_prepend_ui_reference (EggMenuMergeNode *node, + guint merge_id, GQuark action_quark) +{ + NodeUIReference *reference; + + reference = g_new (NodeUIReference, 1); + reference->action_quark = action_quark; + reference->merge_id = merge_id; + + /* Prepend the reference */ + node->uifiles = g_list_prepend (node->uifiles, reference); + + node->dirty = TRUE; +} + +static void +egg_menu_merge_node_remove_ui_reference (EggMenuMergeNode *node, + guint merge_id) +{ + GList *p; + + for (p = node->uifiles; p != NULL; p = p->next) + { + NodeUIReference *reference = p->data; + + if (reference->merge_id == merge_id) + { + node->uifiles = g_list_remove_link (node->uifiles, p); + node->dirty = TRUE; + g_free (reference); + + break; + } + } +} + +/* -------------------- The UI file parser -------------------- */ + +typedef enum { + STATE_START, + STATE_ROOT, + STATE_MENU, + STATE_TOOLBAR, + STATE_POPUPS, + STATE_MENUITEM, + STATE_TOOLITEM, + STATE_END +} ParseState; + +typedef struct _ParseContext ParseContext; +struct _ParseContext +{ + ParseState state; + ParseState prev_state; + + EggMenuMerge *self; + + GNode *current; + + guint merge_id; +}; + +static void +start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + EggMenuMerge *self = ctx->self; + + gint i; + const gchar *node_name; + GQuark verb_quark; + gboolean top; + + gboolean raise_error = TRUE; + gchar *error_attr = NULL; + + //g_message("starting element %s", element_name); + + /* work out a name for this node. Either the name attribute, or + * element name */ + node_name = element_name; + verb_quark = 0; + top = FALSE; + for (i = 0; attribute_names[i] != NULL; i++) + { + if (!strcmp(attribute_names[i], "name")) + { + node_name = attribute_values[i]; + } + else if (!strcmp(attribute_names[i], "verb")) + { + verb_quark = g_quark_from_string(attribute_values[i]); + } + else if (!strcmp(attribute_names[i], "pos")) + { + top = !strcmp(attribute_values[i], "top"); + } + } + /* if no verb, then set it to the node's name */ + if (verb_quark == 0) + verb_quark = g_quark_from_string(node_name); + + switch (element_name[0]) + { + case 'R': + if (ctx->state == STATE_START && !strcmp(element_name, "Root")) + { + ctx->state = STATE_ROOT; + ctx->current = self->root_node; + raise_error = FALSE; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), + ctx->merge_id, verb_quark); + } + break; + case 'm': + if (ctx->state == STATE_ROOT && !strcmp(element_name, "menu")) + { + ctx->state = STATE_MENU; + ctx->current = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_MENUBAR, + TRUE, FALSE); + if (NODE_INFO(ctx->current)->action_name == 0) + NODE_INFO(ctx->current)->action_name = verb_quark; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), + ctx->merge_id, verb_quark); + NODE_INFO(ctx->current)->dirty = TRUE; + + raise_error = FALSE; + } + else if (ctx->state == STATE_MENU && !strcmp(element_name, "menuitem")) + { + GNode *node; + + ctx->state = STATE_MENUITEM; + node = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_MENUITEM, + TRUE, top); + if (NODE_INFO(node)->action_name == 0) + NODE_INFO(node)->action_name = verb_quark; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (node), + ctx->merge_id, verb_quark); + NODE_INFO(node)->dirty = TRUE; + + raise_error = FALSE; + } + break; + case 'd': + if (ctx->state == STATE_ROOT && !strcmp(element_name, "dockitem")) + { + ctx->state = STATE_TOOLBAR; + ctx->current = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_TOOLBAR, + TRUE, FALSE); + if (NODE_INFO(ctx->current)->action_name == 0) + NODE_INFO(ctx->current)->action_name = verb_quark; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), + ctx->merge_id, verb_quark); + NODE_INFO(ctx->current)->dirty = TRUE; + + raise_error = FALSE; + } + break; + case 'p': + if (ctx->state == STATE_ROOT && !strcmp(element_name, "popups")) + { + ctx->state = STATE_POPUPS; + ctx->current = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_POPUPS, + TRUE, FALSE); + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), + ctx->merge_id, verb_quark); + NODE_INFO(ctx->current)->dirty = TRUE; + + raise_error = FALSE; + } + else if (ctx->state == STATE_POPUPS && !strcmp(element_name, "popup")) + { + ctx->state = STATE_MENU; + ctx->current = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_MENU, + TRUE, FALSE); + if (NODE_INFO(ctx->current)->action_name == 0) + NODE_INFO(ctx->current)->action_name = verb_quark; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), + ctx->merge_id, verb_quark); + NODE_INFO(ctx->current)->dirty = TRUE; + + raise_error = FALSE; + } + else if ((ctx->state == STATE_MENU || ctx->state == STATE_TOOLBAR) && + !strcmp(element_name, "placeholder")) + { + if (ctx->state == STATE_MENU) + ctx->current = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_MENU_PLACEHOLDER, + TRUE, top); + else + ctx->current = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER, + TRUE, top); + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), + ctx->merge_id, verb_quark); + NODE_INFO(ctx->current)->dirty = TRUE; + + raise_error = FALSE; + } + break; + case 's': + if (ctx->state == STATE_MENU && !strcmp(element_name, "submenu")) + { + ctx->state = STATE_MENU; + ctx->current = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_MENU, + TRUE, top); + if (NODE_INFO(ctx->current)->action_name == 0) + NODE_INFO(ctx->current)->action_name = verb_quark; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (ctx->current), + ctx->merge_id, verb_quark); + NODE_INFO(ctx->current)->dirty = TRUE; + + raise_error = FALSE; + } + else if ((ctx->state == STATE_MENU || ctx->state == STATE_TOOLBAR) && + !strcmp(element_name, "separator")) + { + GNode *node; + + if (ctx->state == STATE_MENU) + ctx->state = STATE_MENUITEM; + else + ctx->state = STATE_TOOLITEM; + node = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_SEPARATOR, + TRUE, top); + if (NODE_INFO(node)->action_name == 0) + NODE_INFO(node)->action_name = verb_quark; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (node), + ctx->merge_id, verb_quark); + NODE_INFO(node)->dirty = TRUE; + + raise_error = FALSE; + } + break; + case 't': + if (ctx->state == STATE_TOOLBAR && !strcmp(element_name, "toolitem")) + { + GNode *node; + + ctx->state = STATE_TOOLITEM; + node = get_child_node(self, ctx->current, + node_name, strlen(node_name), + EGG_MENU_MERGE_TOOLITEM, + TRUE, top); + if (NODE_INFO(node)->action_name == 0) + NODE_INFO(node)->action_name = verb_quark; + + egg_menu_merge_node_prepend_ui_reference (NODE_INFO (node), + ctx->merge_id, verb_quark); + NODE_INFO(node)->dirty = TRUE; + + raise_error = FALSE; + } + break; + default: + break; + } + if (raise_error) + { + gint line_number, char_number; + + g_markup_parse_context_get_position (context, + &line_number, &char_number); + if (error_attr) + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, + _("Unknown attribute '%s' on line %d char %d"), + error_attr, + line_number, char_number); + else + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_UNKNOWN_ELEMENT, + _("Unknown tag '%s' on line %d char %d"), + element_name, + line_number, char_number); + } +} + +static void +end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + EggMenuMerge *self = ctx->self; + + //g_message("ending element %s (state=%d)", element_name, ctx->state); + + switch (ctx->state) + { + case STATE_START: + g_warning("shouldn't get any end tags in start state"); + /* should we GError here? */ + break; + case STATE_ROOT: + if (ctx->current != self->root_node) + g_warning("we are in STATE_ROOT, but the current node isn't the root"); + ctx->current = NULL; + ctx->state = STATE_END; + break; + case STATE_MENU: + ctx->current = ctx->current->parent; + if (NODE_INFO(ctx->current)->type == EGG_MENU_MERGE_ROOT) /* menubar */ + ctx->state = STATE_ROOT; + else if (NODE_INFO(ctx->current)->type == EGG_MENU_MERGE_POPUPS) /* popup */ + ctx->state = STATE_POPUPS; + /* else, stay in STATE_MENU state */ + break; + case STATE_TOOLBAR: + ctx->current = ctx->current->parent; + /* we conditionalise this test, in case we are closing off a + * placeholder */ + if (NODE_INFO(ctx->current)->type == EGG_MENU_MERGE_ROOT) + ctx->state = STATE_ROOT; + /* else, stay in STATE_TOOLBAR state */ + break; + case STATE_POPUPS: + ctx->current = ctx->current->parent; + ctx->state = STATE_ROOT; + break; + case STATE_MENUITEM: + ctx->state = STATE_MENU; + break; + case STATE_TOOLITEM: + ctx->state = STATE_TOOLBAR; + break; + case STATE_END: + g_warning("shouldn't get any end tags at this point"); + /* should do an error here */ + break; + } +} + +static void +cleanup (GMarkupParseContext *context, + GError *error, + gpointer user_data) +{ + ParseContext *ctx = user_data; + EggMenuMerge *self = ctx->self; + + ctx->current = NULL; + /* should also walk through the tree and get rid of nodes related to + * this UI file's tag */ + + egg_menu_merge_remove_ui (self, ctx->merge_id); +} + +static GMarkupParser ui_parser = { + start_element_handler, + end_element_handler, + NULL, + NULL, + cleanup +}; + +guint +egg_menu_merge_add_ui_from_string (EggMenuMerge *self, + const gchar *buffer, guint length, + GError **error) +{ + ParseContext ctx = { 0 }; + GMarkupParseContext *context; + gboolean res = TRUE; + + g_return_val_if_fail(EGG_IS_MENU_MERGE(self), FALSE); + g_return_val_if_fail(buffer != NULL, FALSE); + + ctx.state = STATE_START; + ctx.self = self; + ctx.current = NULL; + ctx.merge_id = egg_menu_merge_next_merge_id (self); + + context = g_markup_parse_context_new(&ui_parser, 0, &ctx, NULL); + if (length < 0) + length = strlen(buffer); + + if (g_markup_parse_context_parse(context, buffer, length, error)) + { + if (!g_markup_parse_context_end_parse(context, error)) + res = FALSE; + } + else + res = FALSE; + + g_markup_parse_context_free (context); + + egg_menu_merge_queue_update(self); + + if (res) + return ctx.merge_id; + return 0; +} + +guint +egg_menu_merge_add_ui_from_file (EggMenuMerge *self, + const gchar *filename, + GError **error) +{ + gchar *buffer; + gint length; + guint res; + + if (!g_file_get_contents (filename, &buffer, &length, error)) + return 0; + + res = egg_menu_merge_add_ui_from_string(self, buffer, length, error); + g_free(buffer); + + return res; +} + +static gboolean +remove_ui (GNode *node, gpointer user_data) +{ + guint merge_id = GPOINTER_TO_UINT (user_data); + + egg_menu_merge_node_remove_ui_reference (NODE_INFO (node), merge_id); + + return FALSE; /* continue */ +} + +void +egg_menu_merge_remove_ui (EggMenuMerge *self, guint merge_id) +{ + g_node_traverse(self->root_node, G_POST_ORDER, G_TRAVERSE_ALL, -1, + remove_ui, GUINT_TO_POINTER (merge_id)); + + egg_menu_merge_queue_update(self); +} + +/* -------------------- Updates -------------------- */ + + +static EggAction * +get_action_by_name (EggMenuMerge *merge, const char *action_name) +{ + GList *tmp; + + if (!action_name) + return NULL; + + /* lookup name */ + for (tmp = merge->action_groups; tmp != NULL; tmp = tmp->next) + { + EggActionGroup *action_group = tmp->data; + EggAction *action; + + action = egg_action_group_get_action (action_group, action_name); + + if (action) + return action; + } + + return NULL; +} + +static gboolean +find_menu_position (GNode *node, GtkWidget **menushell_p, gint *pos_p) +{ + GtkWidget *menushell; + gint pos; + + g_return_val_if_fail(node != NULL, FALSE); + g_return_val_if_fail(NODE_INFO(node)->type == EGG_MENU_MERGE_MENU || + NODE_INFO(node)->type == EGG_MENU_MERGE_MENU_PLACEHOLDER || + NODE_INFO(node)->type == EGG_MENU_MERGE_MENUITEM || + NODE_INFO(node)->type == EGG_MENU_MERGE_SEPARATOR, + FALSE); + + /* first sibling -- look at parent */ + if (node->prev == NULL) + { + GNode *parent; + + parent = node->parent; + switch (NODE_INFO(parent)->type) + { + case EGG_MENU_MERGE_MENUBAR: + menushell = NODE_INFO(parent)->proxy; + pos = 0; + break; + case EGG_MENU_MERGE_MENU: + menushell = NODE_INFO(parent)->proxy; + if (GTK_IS_MENU_ITEM(menushell)) + menushell = gtk_menu_item_get_submenu(GTK_MENU_ITEM(menushell)); + pos = 0; + break; + case EGG_MENU_MERGE_MENU_PLACEHOLDER: + menushell = gtk_widget_get_parent(NODE_INFO(parent)->proxy); + g_return_val_if_fail(GTK_IS_MENU_SHELL(menushell), FALSE); + pos = g_list_index(GTK_MENU_SHELL(menushell)->children, + NODE_INFO(parent)->proxy) + 1; + break; + default: + g_warning("%s: bad parent node type %d", G_STRLOC, + NODE_INFO(parent)->type); + return FALSE; + } + } + else + { + GtkWidget *prev_child; + GNode *sibling; + + sibling = node->prev; + if (NODE_INFO(sibling)->type == EGG_MENU_MERGE_MENU_PLACEHOLDER) + prev_child = NODE_INFO(sibling)->extra; /* second Separator */ + else + prev_child = NODE_INFO(sibling)->proxy; + + g_return_val_if_fail(GTK_IS_WIDGET(prev_child), FALSE); + menushell = gtk_widget_get_parent(prev_child); + g_return_val_if_fail(GTK_IS_MENU_SHELL(menushell), FALSE); + + pos = g_list_index(GTK_MENU_SHELL(menushell)->children, prev_child) + 1; + } + + if (menushell_p) + *menushell_p = menushell; + if (pos_p) + *pos_p = pos; + + return TRUE; +} + +static gboolean +find_toolbar_position (GNode *node, GtkWidget **toolbar_p, gint *pos_p) +{ + GtkWidget *toolbar; + gint pos; + + g_return_val_if_fail(node != NULL, FALSE); + g_return_val_if_fail(NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLBAR || + NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER || + NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLITEM || + NODE_INFO(node)->type == EGG_MENU_MERGE_SEPARATOR, + FALSE); + + /* first sibling -- look at parent */ + if (node->prev == NULL) + { + GNode *parent; + + parent = node->parent; + switch (NODE_INFO(parent)->type) + { + case EGG_MENU_MERGE_TOOLBAR: + toolbar = NODE_INFO(parent)->proxy; + pos = 0; + break; + case EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER: + toolbar = gtk_widget_get_parent(NODE_INFO(parent)->proxy); + g_return_val_if_fail(EGG_IS_TOOLBAR(toolbar), FALSE); + pos = g_list_index(egg_toolbar_get_tool_items(EGG_TOOLBAR(toolbar)), + NODE_INFO(parent)->proxy) + 1; + break; + default: + g_warning("%s: bad parent node type %d", G_STRLOC, + NODE_INFO(parent)->type); + return FALSE; + } + } + else + { + GtkWidget *prev_child; + GNode *sibling; + + sibling = node->prev; + if (NODE_INFO(sibling)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) + prev_child = NODE_INFO(sibling)->extra; /* second Separator */ + else + prev_child = NODE_INFO(sibling)->proxy; + + g_return_val_if_fail(GTK_IS_WIDGET(prev_child), FALSE); + toolbar = gtk_widget_get_parent(prev_child); + g_return_val_if_fail(EGG_IS_TOOLBAR(toolbar), FALSE); + + pos = g_list_index(egg_toolbar_get_tool_items(EGG_TOOLBAR(toolbar)), + prev_child) + 1; + } + + if (toolbar_p) + *toolbar_p = toolbar; + if (pos_p) + *pos_p = pos; + + return TRUE; +} + +static void +update_node (EggMenuMerge *self, GNode *node) +{ + EggMenuMergeNode *info; + GNode *child; + EggAction *action; + GList *tmp; + + g_return_if_fail (node != NULL); + g_return_if_fail (NODE_INFO(node) != NULL); + + info = NODE_INFO(node); + + if (NODE_INFO(node)->dirty) + { + const gchar *action_name; + NodeUIReference *ref; + + if (info->uifiles == NULL) { + /* We may need to remove this node. + * This must be done in post order + */ + goto recurse_children; + } + + ref = info->uifiles->data; + action_name = g_quark_to_string (ref->action_quark); + action = get_action_by_name (self, action_name); + + NODE_INFO(node)->dirty = FALSE; + + /* Check if the node doesn't have an action and must have an action */ + if (action == NULL && + info->type != EGG_MENU_MERGE_MENUBAR && + info->type != EGG_MENU_MERGE_TOOLBAR && + info->type != EGG_MENU_MERGE_SEPARATOR && + info->type != EGG_MENU_MERGE_MENU_PLACEHOLDER && + info->type != EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) + { + /* FIXME: Should we warn here? */ + goto recurse_children; + } + + /* If the widget already has a proxy and the action hasn't changed, then + * we don't have to do anything. + */ + if (info->proxy != NULL && + action == info->action) + { + goto recurse_children; + } + + if (info->action) + g_object_unref (info->action); + info->action = action; + if (info->action) + g_object_ref (info->action); + + switch (info->type) + { + case EGG_MENU_MERGE_MENUBAR: + if (info->proxy == NULL) + { + info->proxy = gtk_menu_bar_new (); + gtk_widget_show (info->proxy); + g_signal_emit (self, merge_signals[ADD_WIDGET], 0, info->proxy); + } + break; + case EGG_MENU_MERGE_MENU: + { + GtkWidget *prev_submenu = NULL; + /* remove the proxy if it is of the wrong type ... */ + if (info->proxy && G_OBJECT_TYPE(info->proxy) != + EGG_ACTION_GET_CLASS(info->action)->menu_item_type) + { + prev_submenu = gtk_menu_item_get_submenu(GTK_MENU_ITEM(info->proxy)); + if (prev_submenu) + { + g_object_ref (prev_submenu); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(info->proxy),NULL); + } + gtk_container_remove(GTK_CONTAINER(info->proxy->parent), + info->proxy); + info->proxy = NULL; + } + /* create proxy if needed ... */ + if (info->proxy == NULL) + { + GtkWidget *menushell; + gint pos; + GNode *parent; + + parent = node->parent; + + if (parent && NODE_INFO (parent)->type == EGG_MENU_MERGE_POPUPS) + { + info->proxy = gtk_menu_new(); + } + else if (find_menu_position(node, &menushell, &pos)) + { + GtkWidget *menu; + info->proxy = egg_action_create_menu_item (info->action); + menu = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(info->proxy), menu); + gtk_menu_set_accel_group (GTK_MENU (menu), self->accel_group); + gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), + info->proxy, pos); + } + } + else + { + egg_action_connect_proxy (info->action, info->proxy); + } + if (prev_submenu) + { + gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), + prev_submenu); + g_object_unref (prev_submenu); + } + } + break; + case EGG_MENU_MERGE_UNDECIDED: + g_warning("found 'undecided node!"); + break; + case EGG_MENU_MERGE_ROOT: + break; + case EGG_MENU_MERGE_TOOLBAR: + if (info->proxy == NULL) + { + info->proxy = egg_toolbar_new (); + gtk_widget_show (info->proxy); + g_signal_emit (self, merge_signals[ADD_WIDGET], 0, info->proxy); + } + break; + case EGG_MENU_MERGE_MENU_PLACEHOLDER: + /* create menu items for placeholders if necessary ... */ + if (!GTK_IS_SEPARATOR_MENU_ITEM (info->proxy) || + !GTK_IS_SEPARATOR_MENU_ITEM (info->extra)) + { + if (info->proxy) + gtk_container_remove(GTK_CONTAINER(info->proxy->parent), + info->proxy); + if (info->extra) + gtk_container_remove(GTK_CONTAINER(info->extra->parent), + info->extra); + info->proxy = NULL; + info->extra = NULL; + } + if (info->proxy == NULL) + { + GtkWidget *menushell; + gint pos; + + if (find_menu_position(node, &menushell, &pos)) + { + NODE_INFO(node)->proxy = gtk_separator_menu_item_new(); + gtk_menu_shell_insert(GTK_MENU_SHELL(menushell), + NODE_INFO(node)->proxy, pos); + //gtk_widget_show(NODE_INFO(node)->proxy); + + NODE_INFO(node)->extra = gtk_separator_menu_item_new(); + gtk_menu_shell_insert(GTK_MENU_SHELL(menushell), + NODE_INFO(node)->extra, pos+1); + //gtk_widget_show(NODE_INFO(node)->extra); + } + } + break; + case EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER: + /* create toolbar items for placeholders if necessary ... */ + if (!EGG_IS_SEPARATOR_TOOL_ITEM (info->proxy) || + !EGG_IS_SEPARATOR_TOOL_ITEM (info->extra)) + { + if (info->proxy) + gtk_container_remove(GTK_CONTAINER(info->proxy->parent), + info->proxy); + if (info->extra) + gtk_container_remove(GTK_CONTAINER(info->extra->parent), + info->extra); + info->proxy = NULL; + info->extra = NULL; + } + if (info->proxy == NULL) + { + GtkWidget *toolbar; + gint pos; + + if (find_toolbar_position(node, &toolbar, &pos)) + { + EggToolItem *item; + + item = egg_separator_tool_item_new(); + egg_toolbar_insert_tool_item(EGG_TOOLBAR(toolbar), item, pos); + NODE_INFO(node)->proxy = GTK_WIDGET (item); + //gtk_widget_show(NODE_INFO(node)->proxy); + + item = egg_separator_tool_item_new(); + egg_toolbar_insert_tool_item(EGG_TOOLBAR(toolbar), item, pos+1); + NODE_INFO(node)->extra = GTK_WIDGET (item); + //gtk_widget_show(NODE_INFO(node)->extra); + } + } + break; + case EGG_MENU_MERGE_POPUPS: + break; + case EGG_MENU_MERGE_MENUITEM: + /* remove the proxy if it is of the wrong type ... */ + if (info->proxy && G_OBJECT_TYPE(info->proxy) != + EGG_ACTION_GET_CLASS(info->action)->menu_item_type) + { + gtk_container_remove(GTK_CONTAINER(info->proxy->parent), + info->proxy); + info->proxy = NULL; + } + /* create proxy if needed ... */ + if (info->proxy == NULL) + { + GtkWidget *menushell; + gint pos; + + if (find_menu_position(node, &menushell, &pos)) + { + info->proxy = egg_action_create_menu_item (info->action); + + gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), + info->proxy, pos); + } + } + else + { + gtk_menu_item_set_submenu(GTK_MENU_ITEM(info->proxy), NULL); + egg_action_connect_proxy (info->action, info->proxy); + } + break; + case EGG_MENU_MERGE_TOOLITEM: + /* remove the proxy if it is of the wrong type ... */ + if (info->proxy && G_OBJECT_TYPE(info->proxy) != + EGG_ACTION_GET_CLASS(info->action)->toolbar_item_type) + { + gtk_container_remove(GTK_CONTAINER(info->proxy->parent), + info->proxy); + info->proxy = NULL; + } + /* create proxy if needed ... */ + if (info->proxy == NULL) + { + GtkWidget *toolbar; + gint pos; + + if (find_toolbar_position(node, &toolbar, &pos)) + { + info->proxy = egg_action_create_tool_item (info->action); + + egg_toolbar_insert_tool_item (EGG_TOOLBAR (toolbar), + EGG_TOOL_ITEM (info->proxy), pos); + } + } + else + { + egg_action_connect_proxy (info->action, info->proxy); + } + break; + case EGG_MENU_MERGE_SEPARATOR: + if (NODE_INFO (node->parent)->type == EGG_MENU_MERGE_TOOLBAR || + NODE_INFO (node->parent)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) + { + GtkWidget *toolbar; + gint pos; + + if (EGG_IS_SEPARATOR_TOOL_ITEM(info->proxy)) + { + gtk_container_remove(GTK_CONTAINER(info->proxy->parent), + info->proxy); + info->proxy = NULL; + } + + if (find_toolbar_position(node, &toolbar, &pos)) + { + EggToolItem *item = egg_separator_tool_item_new(); + egg_toolbar_insert_tool_item (EGG_TOOLBAR (toolbar), item, pos); + info->proxy = GTK_WIDGET (item); + gtk_widget_show(info->proxy); + } + } + else + { + GtkWidget *menushell; + gint pos; + + if (GTK_IS_SEPARATOR_MENU_ITEM(info->proxy)) + { + gtk_container_remove(GTK_CONTAINER(info->proxy->parent), + info->proxy); + info->proxy = NULL; + } + + if (find_menu_position(node, &menushell, &pos)) + { + info->proxy = gtk_separator_menu_item_new(); + gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), + info->proxy, pos); + gtk_widget_show(info->proxy); + } + } + break; + } + + /* if this node has a widget, but it is the wrong type, remove it */ + } + + recurse_children: + /* process children */ + child = node->children; + while (child) + { + GNode *current; + + current = child; + child = current->next; + update_node (self, current); + } + + /* handle cleanup of dead nodes */ + if (node->children == NULL && NODE_INFO(node)->uifiles == NULL) + { + if (NODE_INFO(node)->proxy) + gtk_widget_destroy(NODE_INFO(node)->proxy); + if ((NODE_INFO(node)->type == EGG_MENU_MERGE_MENU_PLACEHOLDER || + NODE_INFO(node)->type == EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER) && + NODE_INFO(node)->extra) + gtk_widget_destroy(NODE_INFO(node)->extra); + g_chunk_free(NODE_INFO(node), merge_node_chunk); + g_node_destroy(node); + } +} + +static gboolean +do_updates(EggMenuMerge *self) +{ + /* this function needs to check through the tree for dirty nodes. + * For such nodes, it needs to do the following: + * + * 1) check if they are referenced by any loaded UI files anymore. + * In which case, the proxy widget should be destroyed, unless + * there are any subnodes. + * + * 2) lookup the action for this node again. If it is different to + * the current one (or if no previous action has been looked up), + * the proxy is reconnected to the new action (or a new proxy widget + * is created and added to the parent container). + */ + + g_message("do_updates"); + + update_node (self, self->root_node); + + self->update_tag = 0; + return FALSE; +} + +static void +egg_menu_merge_queue_update (EggMenuMerge *self) +{ + if (self->update_tag != 0) + return; + + self->update_tag = g_idle_add((GSourceFunc)do_updates, self); +} + +void +egg_menu_merge_ensure_update (EggMenuMerge *self) +{ + if (self->update_tag != 0) + { + g_source_remove(self->update_tag); + do_updates(self); + } +} + +static gboolean +dirty_traverse_func (GNode *node, gpointer data) +{ + NODE_INFO(node)->dirty = TRUE; + return FALSE; +} + +static void +egg_menu_merge_dirty_all (EggMenuMerge *self) +{ + g_node_traverse(self->root_node, G_PRE_ORDER, G_TRAVERSE_ALL, -1, + dirty_traverse_func, NULL); + egg_menu_merge_queue_update(self); +} diff --git a/lib/egg/egg-menu-merge.h b/lib/egg/egg-menu-merge.h new file mode 100644 index 000000000..f4c440706 --- /dev/null +++ b/lib/egg/egg-menu-merge.h @@ -0,0 +1,100 @@ +#ifndef EGG_MENU_MERGE_H +#define EGG_MENU_MERGE_H + +#include <glib.h> +#include <glib-object.h> + +#include <egg-action.h> +#include <egg-action-group.h> + +#define EGG_TYPE_MENU_MERGE (egg_menu_merge_get_type ()) +#define EGG_MENU_MERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_MENU_MERGE, EggMenuMerge)) +#define EGG_MENU_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_MENU_MERGE, EggMenuMergeClass)) +#define EGG_IS_MENU_MERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_MENU_MERGE)) +#define EGG_IS_MENU_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_MENU_MERGE)) +#define EGG_MENU_MERGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_MENU_MERGE, EggMenuMergeClass)) + +typedef struct _EggMenuMerge EggMenuMerge; +typedef struct _EggMenuMergeClass EggMenuMergeClass; +typedef struct _EggMenuMergeNode EggMenuMergeNode; + +typedef enum { + EGG_MENU_MERGE_UNDECIDED, + EGG_MENU_MERGE_ROOT, + EGG_MENU_MERGE_MENUBAR, + EGG_MENU_MERGE_MENU, + EGG_MENU_MERGE_TOOLBAR, + EGG_MENU_MERGE_MENU_PLACEHOLDER, + EGG_MENU_MERGE_TOOLBAR_PLACEHOLDER, + EGG_MENU_MERGE_POPUPS, + EGG_MENU_MERGE_MENUITEM, + EGG_MENU_MERGE_TOOLITEM, + EGG_MENU_MERGE_SEPARATOR, +} EggMenuMergeNodeType; + +struct _EggMenuMerge { + GObject parent; + + GtkAccelGroup *accel_group; + + GNode *root_node; + GList *action_groups; + + guint last_merge_id; + + guint update_tag; +}; + +struct _EggMenuMergeClass { + GObjectClass parent_class; + + void (* add_widget) (EggMenuMerge *merge, GtkWidget *widget); + void (* remove_widget) (EggMenuMerge *merge, GtkWidget *widget); +}; + +struct _EggMenuMergeNode { + EggMenuMergeNodeType type; + + const gchar *name; + + GQuark action_name; + EggAction *action; + GtkWidget *proxy; + GtkWidget *extra; /*GtkMenu for submenus, second separator for placeholders*/ + + GList *uifiles; + + guint dirty : 1; +}; + +GType egg_menu_merge_get_type (void); +EggMenuMerge *egg_menu_merge_new (void); + +/* these two functions will dirty all merge nodes, as they may need to + * be connected up to different actions */ +void egg_menu_merge_insert_action_group (EggMenuMerge *self, + EggActionGroup *action_group, + gint pos); +void egg_menu_merge_remove_action_group (EggMenuMerge *self, + EggActionGroup*action_group); + + +GtkWidget *egg_menu_merge_get_widget (EggMenuMerge *self, + const gchar *path); + +/* these two functions are for adding UI elements to the merged user + * interface */ +guint egg_menu_merge_add_ui_from_string (EggMenuMerge *self, + const gchar *buffer, + guint length, + GError **error); +guint egg_menu_merge_add_ui_from_file (EggMenuMerge *self, + const gchar *filename, + GError **error); +void egg_menu_merge_remove_ui (EggMenuMerge *self, + guint merge_id); + +void egg_menu_merge_ensure_update (EggMenuMerge *self); + + +#endif /* EGG_MENU_MERGE_H */ diff --git a/lib/egg/egg-menu.h b/lib/egg/egg-menu.h new file mode 100644 index 000000000..eb71ef66d --- /dev/null +++ b/lib/egg/egg-menu.h @@ -0,0 +1,13 @@ +#ifndef EGG_MENU_H +#define EGG_MENU_H + +#include <libegg/menu/egg-action.h> +#include <libegg/menu/egg-toggle-action.h> +#include <libegg/menu/egg-radio-action.h> +#include <libegg/menu/egg-action-group.h> + +#include <libegg/menu/egg-menu-merge.h> + +#include <libegg/menu/egg-accel-dialog.h> + +#endif diff --git a/lib/egg/egg-radio-action.c b/lib/egg/egg-radio-action.c new file mode 100644 index 000000000..888448c50 --- /dev/null +++ b/lib/egg/egg-radio-action.c @@ -0,0 +1,194 @@ +#include "egg-radio-action.h" + +static void egg_radio_action_init (EggRadioAction *action); +static void egg_radio_action_class_init (EggRadioActionClass *class); + +GType +egg_radio_action_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggRadioActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_radio_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (EggRadioAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_radio_action_init, + }; + + type = g_type_register_static (EGG_TYPE_TOGGLE_ACTION, + "EggRadioAction", + &type_info, 0); + } + return type; +} + +static void egg_radio_action_finalize (GObject *object); +static void egg_radio_action_activate (EggAction *action); + +static GObjectClass *parent_class = NULL; + +static void +egg_radio_action_class_init (EggRadioActionClass *class) +{ + GObjectClass *object_class; + EggActionClass *action_class; + + parent_class = g_type_class_peek_parent (class); + object_class = G_OBJECT_CLASS (class); + action_class = EGG_ACTION_CLASS (class); + + object_class->finalize = egg_radio_action_finalize; + + action_class->activate = egg_radio_action_activate; +} + +static void +egg_radio_action_init (EggRadioAction *action) +{ + action->group = g_slist_prepend (NULL, action); +} + +static void +egg_radio_action_finalize (GObject *object) +{ + EggRadioAction *action; + GSList *tmp_list; + + g_return_if_fail (EGG_IS_RADIO_ACTION (object)); + + action = EGG_RADIO_ACTION (object); + + action->group = g_slist_remove (action->group, action); + + tmp_list = action->group; + + while (tmp_list) + { + EggRadioAction *tmp_action = tmp_list->data; + + tmp_list = tmp_list->next; + tmp_action->group = action->group; + } + + if (parent_class->finalize) + (* parent_class->finalize) (object); +} + +static void +egg_radio_action_activate (EggAction *action) +{ + EggRadioAction *radio_action; + EggToggleAction *toggle_action; + EggToggleAction *tmp_action; + GSList *tmp_list; + + g_return_if_fail (EGG_IS_RADIO_ACTION (action)); + + radio_action = EGG_RADIO_ACTION (action); + toggle_action = EGG_TOGGLE_ACTION (action); + + if (toggle_action->active) + { + tmp_list = radio_action->group; + + while (tmp_list) + { + tmp_action = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_action->active && (tmp_action != toggle_action)) + { + toggle_action->active = !toggle_action->active; + break; + } + } + } + else + { + toggle_action->active = !toggle_action->active; + + tmp_list = radio_action->group; + while (tmp_list) + { + tmp_action = tmp_list->data; + tmp_list = tmp_list->next; + + if (tmp_action->active && (tmp_action != toggle_action)) + { + egg_action_activate (EGG_ACTION (tmp_action)); + break; + } + } + } + + egg_toggle_action_toggled (toggle_action); +} + +/** + * egg_radio_action_get_group: + * @action: the action object + * + * Returns: the list representing the radio group for this object + */ +GSList * +egg_radio_action_get_group (EggRadioAction *action) +{ + g_return_val_if_fail (EGG_IS_RADIO_ACTION (action), NULL); + + return action->group; +} + +/** + * egg_radio_action_set_group: + * @action: the action object + * @group: a list representing a radio group + * + * Sets the radio group for the radio action object. + */ +void +egg_radio_action_set_group (EggRadioAction *action, GSList *group) +{ + g_return_if_fail (EGG_IS_RADIO_ACTION (action)); + g_return_if_fail (!g_slist_find (group, action)); + + if (action->group) + { + GSList *slist; + + action->group = g_slist_remove (action->group, action); + + for (slist = action->group; slist; slist = slist->next) + { + EggRadioAction *tmp_action = slist->data; + + tmp_action->group = action->group; + } + } + + action->group = g_slist_prepend (group, action); + + if (group) + { + GSList *slist; + + for (slist = action->group; slist; slist = slist->next) + { + EggRadioAction *tmp_action = slist->data; + + tmp_action->group = action->group; + } + } + else + { + EGG_TOGGLE_ACTION (action)->active = TRUE; + } +} diff --git a/lib/egg/egg-radio-action.h b/lib/egg/egg-radio-action.h new file mode 100644 index 000000000..6fe097be5 --- /dev/null +++ b/lib/egg/egg-radio-action.h @@ -0,0 +1,34 @@ +#ifndef EGG_RADIO_ACTION_H +#define EGG_RADIO_ACTION_H + +#include <gtk/gtk.h> +#include <egg-action.h> +#include <egg-toggle-action.h> + +#define EGG_TYPE_RADIO_ACTION (egg_radio_action_get_type ()) +#define EGG_RADIO_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_RADIO_ACTION, EggRadioAction)) +#define EGG_RADIO_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_RADIO_ACTION, EggRadioActionClass)) +#define EGG_IS_RADIO_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_RADIO_ACTION)) +#define EGG_IS_RADIO_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_RADIO_ACTION)) +#define EGG_RADIO_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_RADIO_ACTION, EggRadioActionClass)) + +typedef struct _EggRadioAction EggRadioAction; +typedef struct _EggRadioActionClass EggRadioActionClass; + +struct _EggRadioAction { + EggToggleAction parent; + + GSList *group; +}; + +struct _EggRadioActionClass { + EggToggleActionClass parent_class; +}; + +GType egg_radio_action_get_type (void); + +GSList *egg_radio_action_get_group (EggRadioAction *action); +void egg_radio_action_set_group (EggRadioAction *action, + GSList *group); + +#endif diff --git a/lib/egg/egg-toggle-action.c b/lib/egg/egg-toggle-action.c new file mode 100644 index 000000000..6c0c0b442 --- /dev/null +++ b/lib/egg/egg-toggle-action.c @@ -0,0 +1,197 @@ +#include "egg-toggle-action.h" +#include "eggtoggletoolbutton.h" + +enum { + TOGGLED, + LAST_SIGNAL +}; + +static void egg_toggle_action_init (EggToggleAction *action); +static void egg_toggle_action_class_init (EggToggleActionClass *class); + +GType +egg_toggle_action_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggToggleActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_toggle_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (EggToggleAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_toggle_action_init, + }; + + type = g_type_register_static (EGG_TYPE_ACTION, + "EggToggleAction", + &type_info, 0); + } + return type; +} + +static void egg_toggle_action_activate (EggAction *action); +static void egg_toggle_action_real_toggled (EggToggleAction *action); +static void connect_proxy (EggAction *action, + GtkWidget *proxy); +static void disconnect_proxy (EggAction *action, + GtkWidget *proxy); + +static GObjectClass *parent_class = NULL; +static guint action_signals[LAST_SIGNAL] = { 0 }; + +static void +egg_toggle_action_class_init (EggToggleActionClass *class) +{ + EggActionClass *action_class; + + parent_class = g_type_class_peek_parent (class); + action_class = EGG_ACTION_CLASS (class); + + action_class->activate = egg_toggle_action_activate; + action_class->connect_proxy = connect_proxy; + action_class->disconnect_proxy = disconnect_proxy; + + action_class->menu_item_type = GTK_TYPE_CHECK_MENU_ITEM; + action_class->toolbar_item_type = EGG_TYPE_TOGGLE_TOOL_BUTTON; + + class->toggled = egg_toggle_action_real_toggled; + + action_signals[TOGGLED] = + g_signal_new ("toggled", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EggToggleActionClass, toggled), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +egg_toggle_action_init (EggToggleAction *action) +{ + action->active = FALSE; +} + +static void +egg_toggle_action_activate (EggAction *action) +{ + EggToggleAction *toggle_action; + + g_return_if_fail (EGG_IS_TOGGLE_ACTION (action)); + + toggle_action = EGG_TOGGLE_ACTION (action); + + toggle_action->active = !toggle_action->active; + + egg_toggle_action_toggled (toggle_action); +} + +static void +egg_toggle_action_real_toggled (EggToggleAction *action) +{ + GSList *slist; + + g_return_if_fail (EGG_IS_TOGGLE_ACTION (action)); + + for (slist = EGG_ACTION (action)->proxies; slist; slist = slist->next) + { + GtkWidget *proxy = slist->data; + + egg_action_block_activate_from (EGG_ACTION (action), proxy); + if (GTK_IS_CHECK_MENU_ITEM (proxy)) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (proxy), + action->active); + else if (EGG_IS_TOGGLE_TOOL_BUTTON (proxy)) + egg_toggle_tool_button_set_active (EGG_TOGGLE_TOOL_BUTTON (proxy), + action->active); + else { + g_warning ("Don't know how to toggle `%s' widgets", + G_OBJECT_TYPE_NAME (proxy)); + } + egg_action_unblock_activate_from (EGG_ACTION (action), proxy); + } +} + +static void +connect_proxy (EggAction *action, GtkWidget *proxy) +{ + EggToggleAction *toggle_action; + + toggle_action = EGG_TOGGLE_ACTION (action); + + /* do this before hand, so that we don't call the "activate" handler */ + if (GTK_IS_MENU_ITEM (proxy)) + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (proxy), + toggle_action->active); + else if (EGG_IS_TOGGLE_TOOL_BUTTON (proxy)) + egg_toggle_tool_button_set_active (EGG_TOGGLE_TOOL_BUTTON (proxy), + toggle_action->active); + + (* EGG_ACTION_CLASS (parent_class)->connect_proxy) (action, proxy); +} + +static void +disconnect_proxy (EggAction *action, GtkWidget *proxy) +{ + EggToggleAction *toggle_action; + + toggle_action = EGG_TOGGLE_ACTION (action); + + (* EGG_ACTION_CLASS (parent_class)->disconnect_proxy) (action, proxy); +} + +/** + * egg_toggle_action_toggled: + * @action: the action object + * + * Emits the "toggled" signal on the toggle action. + */ +void +egg_toggle_action_toggled (EggToggleAction *action) +{ + g_return_if_fail (EGG_IS_TOGGLE_ACTION (action)); + + g_signal_emit (action, action_signals[TOGGLED], 0); +} + +/** + * egg_toggle_action_set_active: + * @action: the action object + * @is_active: whether the action should be checked or not + * + * Sets the checked state on the toggle action. + */ +void +egg_toggle_action_set_active (EggToggleAction *action, gboolean is_active) +{ + g_return_if_fail (EGG_IS_TOGGLE_ACTION (action)); + + is_active = is_active != 0; + + if (action->active != is_active) + { + egg_action_activate (EGG_ACTION (action)); + } +} + +/** + * egg_toggle_action_get_active: + * @action: the action object + * + * Returns: the checked state of the toggle action + */ +gboolean +egg_toggle_action_get_active (EggToggleAction *action) +{ + g_return_val_if_fail (EGG_IS_TOGGLE_ACTION (action), FALSE); + + return action->active; +} diff --git a/lib/egg/egg-toggle-action.h b/lib/egg/egg-toggle-action.h new file mode 100644 index 000000000..4a5293bfe --- /dev/null +++ b/lib/egg/egg-toggle-action.h @@ -0,0 +1,38 @@ +#ifndef EGG_TOGGLE_ACTION_H +#define EGG_TOGGLE_ACTION_H + +#include <gtk/gtk.h> +#include <egg-action.h> + +#define EGG_TYPE_TOGGLE_ACTION (egg_toggle_action_get_type ()) +#define EGG_TOGGLE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TOGGLE_ACTION, EggToggleAction)) +#define EGG_TOGGLE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TOGGLE_ACTION, EggToggleActionClass)) +#define EGG_IS_TOGGLE_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TOGGLE_ACTION)) +#define EGG_IS_TOGGLE_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_TOGGLE_ACTION)) +#define EGG_TOGGLE_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_TOGGLE_ACTION, EggToggleActionClass)) + +typedef struct _EggToggleAction EggToggleAction; +typedef struct _EggToggleActionClass EggToggleActionClass; + +struct _EggToggleAction +{ + EggAction parent; + + guint active : 1; +}; + +struct _EggToggleActionClass +{ + EggActionClass parent_class; + + void (* toggled) (EggToggleAction *action); +}; + +GType egg_toggle_action_get_type (void); + +void egg_toggle_action_toggled (EggToggleAction *action); +void egg_toggle_action_set_active (EggToggleAction *action, + gboolean is_active); +gboolean egg_toggle_action_get_active (EggToggleAction *action); + +#endif diff --git a/lib/egg/eggmarshalers.c b/lib/egg/eggmarshalers.c new file mode 100644 index 000000000..3cc9b963e --- /dev/null +++ b/lib/egg/eggmarshalers.c @@ -0,0 +1,277 @@ + +#include <glib-object.h> + + +#ifdef G_ENABLE_DEBUG +#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) +#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) +#define g_marshal_value_peek_int(v) g_value_get_int (v) +#define g_marshal_value_peek_uint(v) g_value_get_uint (v) +#define g_marshal_value_peek_long(v) g_value_get_long (v) +#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) +#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) +#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) +#define g_marshal_value_peek_enum(v) g_value_get_enum (v) +#define g_marshal_value_peek_flags(v) g_value_get_flags (v) +#define g_marshal_value_peek_float(v) g_value_get_float (v) +#define g_marshal_value_peek_double(v) g_value_get_double (v) +#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) +#define g_marshal_value_peek_param(v) g_value_get_param (v) +#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) +#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) +#define g_marshal_value_peek_object(v) g_value_get_object (v) +#else /* !G_ENABLE_DEBUG */ +/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. + * Do not access GValues directly in your code. Instead, use the + * g_value_get_*() functions + */ +#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int +#define g_marshal_value_peek_char(v) (v)->data[0].v_int +#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint +#define g_marshal_value_peek_int(v) (v)->data[0].v_int +#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint +#define g_marshal_value_peek_long(v) (v)->data[0].v_long +#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong +#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 +#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 +#define g_marshal_value_peek_enum(v) (v)->data[0].v_int +#define g_marshal_value_peek_flags(v) (v)->data[0].v_uint +#define g_marshal_value_peek_float(v) (v)->data[0].v_float +#define g_marshal_value_peek_double(v) (v)->data[0].v_double +#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer +#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer +#endif /* !G_ENABLE_DEBUG */ + + +/* VOID:OBJECT,OBJECT (eggmarshalers.list:1) */ +void +_egg_marshal_VOID__OBJECT_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_OBJECT) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_OBJECT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_OBJECT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_object (param_values + 2), + data2); +} + +/* VOID:OBJECT,STRING,LONG,LONG (eggmarshalers.list:2) */ +void +_egg_marshal_VOID__OBJECT_STRING_LONG_LONG (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_STRING_LONG_LONG) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + glong arg_3, + glong arg_4, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_STRING_LONG_LONG callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 5); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_STRING_LONG_LONG) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + g_marshal_value_peek_long (param_values + 3), + g_marshal_value_peek_long (param_values + 4), + data2); +} + +/* VOID:OBJECT,LONG (eggmarshalers.list:3) */ +void +_egg_marshal_VOID__OBJECT_LONG (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_LONG) (gpointer data1, + gpointer arg_1, + glong arg_2, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_LONG callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_LONG) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_long (param_values + 2), + data2); +} + +/* VOID:OBJECT,STRING,STRING (eggmarshalers.list:4) */ +void +_egg_marshal_VOID__OBJECT_STRING_STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__OBJECT_STRING_STRING) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_VOID__OBJECT_STRING_STRING callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__OBJECT_STRING_STRING) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_object (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + g_marshal_value_peek_string (param_values + 3), + data2); +} + +/* BOOLEAN:VOID (eggmarshalers.list:5) */ +void +_egg_marshal_BOOLEAN__VOID (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__VOID) (gpointer data1, + gpointer data2); + register GMarshalFunc_BOOLEAN__VOID callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 1); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__VOID) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + data2); + + g_value_set_boolean (return_value, v_return); +} + +/* OBJECT:VOID (eggmarshalers.list:6) */ +void +_egg_marshal_OBJECT__VOID (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef GObject* (*GMarshalFunc_OBJECT__VOID) (gpointer data1, + gpointer data2); + register GMarshalFunc_OBJECT__VOID callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + GObject* v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 1); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_OBJECT__VOID) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + data2); + + g_value_set_object_take_ownership (return_value, v_return); +} + diff --git a/lib/egg/eggmarshalers.h b/lib/egg/eggmarshalers.h new file mode 100644 index 000000000..dac29f1d1 --- /dev/null +++ b/lib/egg/eggmarshalers.h @@ -0,0 +1,60 @@ + +#ifndef ___egg_marshal_MARSHAL_H__ +#define ___egg_marshal_MARSHAL_H__ + +#include <glib-object.h> + +G_BEGIN_DECLS + +/* VOID:OBJECT,OBJECT (eggmarshalers.list:1) */ +extern void _egg_marshal_VOID__OBJECT_OBJECT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,STRING,LONG,LONG (eggmarshalers.list:2) */ +extern void _egg_marshal_VOID__OBJECT_STRING_LONG_LONG (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,LONG (eggmarshalers.list:3) */ +extern void _egg_marshal_VOID__OBJECT_LONG (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:OBJECT,STRING,STRING (eggmarshalers.list:4) */ +extern void _egg_marshal_VOID__OBJECT_STRING_STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* BOOLEAN:VOID (eggmarshalers.list:5) */ +extern void _egg_marshal_BOOLEAN__VOID (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* OBJECT:VOID (eggmarshalers.list:6) */ +extern void _egg_marshal_OBJECT__VOID (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +G_END_DECLS + +#endif /* ___egg_marshal_MARSHAL_H__ */ + diff --git a/lib/egg/eggmarshalers.list b/lib/egg/eggmarshalers.list new file mode 100644 index 000000000..03890af58 --- /dev/null +++ b/lib/egg/eggmarshalers.list @@ -0,0 +1,6 @@ +VOID:OBJECT,OBJECT +VOID:OBJECT,STRING,LONG,LONG +VOID:OBJECT,LONG +VOID:OBJECT,STRING,STRING +BOOLEAN:VOID +OBJECT:VOID diff --git a/lib/egg/eggradiotoolbutton.c b/lib/egg/eggradiotoolbutton.c new file mode 100644 index 000000000..ec14990b8 --- /dev/null +++ b/lib/egg/eggradiotoolbutton.c @@ -0,0 +1,121 @@ +/* eggradiotoolbutton.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "eggradiotoolbutton.h" +#include <gtk/gtkradiobutton.h> + +#ifndef _ +# define _(s) (s) +#endif + +static void egg_radio_tool_button_init (EggRadioToolButton *button); +static void egg_radio_tool_button_class_init (EggRadioToolButtonClass *klass); + +GType +egg_radio_tool_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggRadioToolButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_radio_tool_button_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EggRadioToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_radio_tool_button_init + }; + + type = g_type_register_static (EGG_TYPE_TOGGLE_TOOL_BUTTON, + "EggRadioToolButton", &type_info, 0); + } + return type; +} + + +static void +egg_radio_tool_button_class_init (EggRadioToolButtonClass *klass) +{ + EggToolButtonClass *toolbutton_class; + + toolbutton_class = (EggToolButtonClass *)klass; + + toolbutton_class->button_type = GTK_TYPE_RADIO_BUTTON; +} + +static void +egg_radio_tool_button_init (EggRadioToolButton *button) +{ + gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (EGG_TOOL_BUTTON (button)->button), FALSE); +} + +EggToolItem * +egg_radio_tool_button_new (GSList *group) +{ + EggRadioToolButton *button; + + button = g_object_new (EGG_TYPE_RADIO_TOOL_BUTTON, + NULL); + + egg_radio_tool_button_set_group (button, group); + + return EGG_TOOL_ITEM (button); +} + +EggToolItem * +egg_radio_tool_button_new_from_stock (GSList *group, + const gchar *stock_id) +{ + EggRadioToolButton *button; + + button = g_object_new (EGG_TYPE_RADIO_TOOL_BUTTON, + "stock_id", stock_id, + "use_underline", TRUE, + NULL); + + + egg_radio_tool_button_set_group (button, group); + + return EGG_TOOL_ITEM (button); +} + +GSList * +egg_radio_tool_button_get_group (EggRadioToolButton *button) +{ + g_return_val_if_fail (EGG_IS_RADIO_TOOL_BUTTON (button), NULL); + + return gtk_radio_button_get_group (GTK_RADIO_BUTTON (EGG_TOOL_BUTTON (button)->button)); +} + +void +egg_radio_tool_button_set_group (EggRadioToolButton *button, + GSList *group) +{ + g_return_if_fail (EGG_IS_RADIO_TOOL_BUTTON (button)); + + gtk_radio_button_set_group (GTK_RADIO_BUTTON (EGG_TOOL_BUTTON (button)->button), group); +} + diff --git a/lib/egg/eggradiotoolbutton.h b/lib/egg/eggradiotoolbutton.h new file mode 100644 index 000000000..44f6a4c1f --- /dev/null +++ b/lib/egg/eggradiotoolbutton.h @@ -0,0 +1,57 @@ +/* eggradiotoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_RADIO_TOOL_BUTTON_H__ +#define __EGG_RADIO_TOOL_BUTTON_H__ + +#include "eggtoggletoolbutton.h" + +#define EGG_TYPE_RADIO_TOOL_BUTTON (egg_radio_tool_button_get_type ()) +#define EGG_RADIO_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_RADIO_TOOL_BUTTON, EggRadioToolButton)) +#define EGG_RADIO_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_RADIO_TOOL_BUTTON, EggRadioToolButtonClass)) +#define EGG_IS_RADIO_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_RADIO_TOOL_BUTTON)) +#define EGG_IS_RADIO_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_RADIO_TOOL_BUTTON)) +#define EGG_RADIO_TOOL_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_RADIO_TOOL_BUTTON, EggRadioToolButtonClass)) + +typedef struct _EggRadioToolButton EggRadioToolButton; +typedef struct _EggRadioToolButtonClass EggRadioToolButtonClass; + +struct _EggRadioToolButton +{ + EggToggleToolButton parent; +}; + +struct _EggRadioToolButtonClass +{ + EggToggleToolButtonClass parent_class; +}; + +GType egg_radio_tool_button_get_type (void) G_GNUC_CONST; +EggToolItem *egg_radio_tool_button_new (GSList *group); +EggToolItem *egg_radio_tool_button_new_from_stock (GSList *group, + const gchar *stock_id); + +GSList *egg_radio_tool_button_get_group (EggRadioToolButton *button); +void egg_radio_tool_button_set_group (EggRadioToolButton *button, + GSList *group); + + +#endif /* __EGG_RADIO_TOOL_BUTTON_H__ */ diff --git a/lib/egg/eggseparatortoolitem.c b/lib/egg/eggseparatortoolitem.c new file mode 100644 index 000000000..e3fe098fc --- /dev/null +++ b/lib/egg/eggseparatortoolitem.c @@ -0,0 +1,86 @@ +#include <gtk/gtkseparatormenuitem.h> +#include "eggseparatortoolitem.h" + +#ifndef _ +# define _(s) (s) +#endif + +static void egg_separator_tool_item_init (EggSeparatorToolItem *self); +static void egg_separator_tool_item_class_init (EggSeparatorToolItemClass*class); + +static void egg_separator_tool_item_add (GtkContainer *container, + GtkWidget *child); +static GtkWidget *egg_separator_tool_item_create_menu_proxy (EggToolItem *self); + +static GObjectClass *parent_class = NULL; + + +GType +egg_separator_tool_item_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggSeparatorToolItemClass), + (GBaseInitFunc) 0, + (GBaseFinalizeFunc) 0, + (GClassInitFunc) egg_separator_tool_item_class_init, + (GClassFinalizeFunc) 0, + NULL, + sizeof (EggSeparatorToolItem), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_separator_tool_item_init + }; + + type = g_type_register_static (EGG_TYPE_TOOL_ITEM, + "EggSeparatorToolItem", &type_info, 0); + } + return type; +} + + +static void +egg_separator_tool_item_class_init (EggSeparatorToolItemClass *class) +{ + GtkContainerClass *container_class; + EggToolItemClass *toolitem_class; + + parent_class = g_type_class_peek_parent (class); + container_class = (GtkContainerClass *)class; + toolitem_class = (EggToolItemClass *)class; + + container_class->add = egg_separator_tool_item_add; + toolitem_class->create_menu_proxy = egg_separator_tool_item_create_menu_proxy; +} + +static void +egg_separator_tool_item_init (EggSeparatorToolItem *self) +{ +} + +static void +egg_separator_tool_item_add (GtkContainer *container, GtkWidget *child) +{ + g_warning("attempt to add a child to an EggSeparatorToolItem"); +} + +static GtkWidget * +egg_separator_tool_item_create_menu_proxy (EggToolItem *item) +{ + return gtk_separator_menu_item_new (); +} + + +EggToolItem * +egg_separator_tool_item_new (void) +{ + EggToolItem *self; + + self = g_object_new (EGG_TYPE_SEPARATOR_TOOL_ITEM, + NULL); + + return self; +} diff --git a/lib/egg/eggseparatortoolitem.h b/lib/egg/eggseparatortoolitem.h new file mode 100644 index 000000000..2947b981b --- /dev/null +++ b/lib/egg/eggseparatortoolitem.h @@ -0,0 +1,50 @@ +/* eggtoggletoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_SEPARATOR_TOOL_ITEM_H__ +#define __EGG_SEPARATOR_TOOL_ITEM_H__ + +#include "eggtoolitem.h" + +#define EGG_TYPE_SEPARATOR_TOOL_ITEM (egg_separator_tool_item_get_type ()) +#define EGG_SEPARATOR_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SEPARATOR_TOOL_ITEM, EggSeparatorToolItem)) +#define EGG_SEPARATOR_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SEPARATOR_TOOL_ITEM, EggSeparatorToolItemClass)) +#define EGG_IS_SEPARATOR_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SEPARATOR_TOOL_ITEM)) +#define EGG_IS_SEPARATOR_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_SEPARATOR_TOOL_ITEM)) +#define EGG_SEPARATOR_TOOL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_SEPARATOR_TOOL_ITEM, EggSeparatorToolItemClass)) + +typedef struct _EggSeparatorToolItem EggSeparatorToolItem; +typedef struct _EggSeparatorToolItemClass EggSeparatorToolItemClass; + +struct _EggSeparatorToolItem +{ + EggToolItem parent; +}; + +struct _EggSeparatorToolItemClass +{ + EggToolItemClass parent_class; +}; + +GType egg_separator_tool_item_get_type (void) G_GNUC_CONST; +EggToolItem *egg_separator_tool_item_new (void); + +#endif /* __EGG_SEPARATOR_TOOL_ITEM_H__ */ diff --git a/lib/egg/eggtoggletoolbutton.c b/lib/egg/eggtoggletoolbutton.c new file mode 100644 index 000000000..c694eb9ad --- /dev/null +++ b/lib/egg/eggtoggletoolbutton.c @@ -0,0 +1,192 @@ +/* eggtoggletoolbutton.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "eggtoggletoolbutton.h" +#include <gtk/gtkcheckmenuitem.h> +#include <gtk/gtklabel.h> +#include <gtk/gtktogglebutton.h> + +#ifndef _ +# define _(s) (s) +#endif + +enum { + TOGGLED, + LAST_SIGNAL +}; + +static void egg_toggle_tool_button_init (EggToggleToolButton *button); +static void egg_toggle_tool_button_class_init (EggToggleToolButtonClass *klass); + +static GtkWidget *egg_toggle_tool_button_create_menu_proxy (EggToolItem *button); + + +static void button_toggled (GtkWidget *widget, + EggToggleToolButton *button); + + + +static GObjectClass *parent_class = NULL; +static guint toggle_signals[LAST_SIGNAL] = { 0 }; + +GType +egg_toggle_tool_button_get_type (void) +{ + static GType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggToggleToolButtonClass), + (GBaseInitFunc) 0, + (GBaseFinalizeFunc) 0, + (GClassInitFunc) egg_toggle_tool_button_class_init, + (GClassFinalizeFunc) 0, + NULL, + sizeof (EggToggleToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_toggle_tool_button_init + }; + + type = g_type_register_static (EGG_TYPE_TOOL_BUTTON, + "EggToggleToolButton", &type_info, 0); + } + return type; +} + + +static void +egg_toggle_tool_button_class_init (EggToggleToolButtonClass *klass) +{ + EggToolItemClass *toolitem_class; + EggToolButtonClass *toolbutton_class; + + parent_class = g_type_class_peek_parent (klass); + + toolitem_class = (EggToolItemClass *)klass; + toolbutton_class = (EggToolButtonClass *)klass; + + toolitem_class->create_menu_proxy = egg_toggle_tool_button_create_menu_proxy; + toolbutton_class->button_type = GTK_TYPE_TOGGLE_BUTTON; + + toggle_signals[TOGGLED] = + g_signal_new ("toggled", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EggToggleToolButtonClass, toggled), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +egg_toggle_tool_button_init (EggToggleToolButton *button) +{ + g_signal_connect_object (EGG_TOOL_BUTTON (button)->button, "toggled", + G_CALLBACK (button_toggled), button, 0); +} + +static GtkWidget * +egg_toggle_tool_button_create_menu_proxy (EggToolItem *item) +{ + EggToggleToolButton *button = EGG_TOGGLE_TOOL_BUTTON (item); + GtkWidget *menu_item; + const char *label; + + label = gtk_label_get_text (GTK_LABEL (EGG_TOOL_BUTTON (button)->label)); + + menu_item = gtk_check_menu_item_new_with_mnemonic (label); + gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menu_item), + button->active); + g_signal_connect_object (menu_item, "activate", + G_CALLBACK (gtk_button_clicked), + EGG_TOOL_BUTTON (button)->button, + G_CONNECT_SWAPPED); + + return menu_item; +} + +static void +button_toggled (GtkWidget *widget, + EggToggleToolButton *button) +{ + gboolean toggle_active; + + toggle_active = GTK_TOGGLE_BUTTON (widget)->active; + if (toggle_active != button->active) + { + button->active = toggle_active; + g_signal_emit (G_OBJECT (button), toggle_signals[TOGGLED], 0); + } +} + +EggToolItem * +egg_toggle_tool_button_new (void) +{ + EggToolButton *button; + + button = g_object_new (EGG_TYPE_TOGGLE_TOOL_BUTTON, + NULL); + + return EGG_TOOL_ITEM (button); +} + +EggToolItem * +egg_toggle_tool_button_new_from_stock (const gchar *stock_id) +{ + EggToolButton *button; + + button = g_object_new (EGG_TYPE_TOGGLE_TOOL_BUTTON, + "stock_id", stock_id, + "use_underline", TRUE, + NULL); + + return EGG_TOOL_ITEM (button); +} + +void +egg_toggle_tool_button_toggled (EggToggleToolButton *button) +{ + g_return_if_fail (EGG_IS_TOGGLE_TOOL_BUTTON (button)); + + gtk_toggle_button_toggled (GTK_TOGGLE_BUTTON(EGG_TOOL_BUTTON(button)->button)); +} + +void +egg_toggle_tool_button_set_active (EggToggleToolButton *button, + gboolean is_active) +{ + g_return_if_fail (EGG_IS_TOGGLE_TOOL_BUTTON (button)); + + is_active = is_active != FALSE; + + if (button->active != is_active) + gtk_button_clicked (GTK_BUTTON (EGG_TOOL_BUTTON (button)->button)); +} + +gboolean +egg_toggle_tool_button_get_active (EggToggleToolButton *button) +{ + g_return_val_if_fail (EGG_IS_TOGGLE_TOOL_BUTTON (button), FALSE); + + return button->active; +} diff --git a/lib/egg/eggtoggletoolbutton.h b/lib/egg/eggtoggletoolbutton.h new file mode 100644 index 000000000..587d42257 --- /dev/null +++ b/lib/egg/eggtoggletoolbutton.h @@ -0,0 +1,64 @@ +/* eggtoggletoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TOGGLE_TOOL_BUTTON_H__ +#define __EGG_TOGGLE_TOOL_BUTTON_H__ + +#include "eggtoolbutton.h" + +G_BEGIN_DECLS + +#define EGG_TYPE_TOGGLE_TOOL_BUTTON (egg_toggle_tool_button_get_type ()) +#define EGG_TOGGLE_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TOGGLE_TOOL_BUTTON, EggToggleToolButton)) +#define EGG_TOGGLE_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TOGGLE_TOOL_BUTTON, EggToggleToolButtonClass)) +#define EGG_IS_TOGGLE_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TOGGLE_TOOL_BUTTON)) +#define EGG_IS_TOGGLE_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_TOGGLE_TOOL_BUTTON)) +#define EGG_TOGGLE_TOOL_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_TOGGLE_TOOL_BUTTON, EggToggleToolButtonClass)) + +typedef struct _EggToggleToolButton EggToggleToolButton; +typedef struct _EggToggleToolButtonClass EggToggleToolButtonClass; + +struct _EggToggleToolButton +{ + EggToolButton parent; + + guint active : 1; +}; + +struct _EggToggleToolButtonClass +{ + EggToolButtonClass parent_class; + + void (* toggled) (EggToggleToolButton *button); +}; + +GType egg_toggle_tool_button_get_type (void) G_GNUC_CONST; +EggToolItem *egg_toggle_tool_button_new (void); +EggToolItem *egg_toggle_tool_button_new_from_stock (const gchar *stock_id); + +void egg_toggle_tool_button_toggled (EggToggleToolButton *button); +void egg_toggle_tool_button_set_active (EggToggleToolButton *button, + gboolean is_active); +gboolean egg_toggle_tool_button_get_active (EggToggleToolButton *button); + +G_END_DECLS + +#endif /* __EGG_TOGGLE_TOOL_BUTTON_H__ */ diff --git a/lib/egg/eggtoolbar.c b/lib/egg/eggtoolbar.c new file mode 100644 index 000000000..3f90fed6a --- /dev/null +++ b/lib/egg/eggtoolbar.c @@ -0,0 +1,1850 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * GtkToolbar copyright (C) Federico Mena + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#include <gtk/gtkarrow.h> +#include "eggtoolbar.h" +#include "eggradiotoolbutton.h" +#include "eggseparatortoolitem.h" +#include <gtk/gtkmenu.h> +#include <gtk/gtkradiobutton.h> +#include <gtk/gtktoolbar.h> + +#define DEFAULT_IPADDING 0 +#define DEFAULT_SPACE_SIZE 5 +#define DEFAULT_SPACE_STYLE GTK_TOOLBAR_SPACE_LINE + +#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_LARGE_TOOLBAR +#define DEFAULT_TOOLBAR_STYLE GTK_TOOLBAR_BOTH + +#define SPACE_LINE_DIVISION 10 +#define SPACE_LINE_START 3 +#define SPACE_LINE_END 7 + +#define TOOLBAR_ITEM_VISIBLE(item) \ +(GTK_WIDGET_VISIBLE (item) && \ +((toolbar->orientation == GTK_ORIENTATION_HORIZONTAL && item->visible_horizontal) || \ + (toolbar->orientation == GTK_ORIENTATION_VERTICAL && item->visible_vertical))) + +#ifndef _ +# define _(s) (s) +#endif + +enum { + PROP_0, + PROP_ORIENTATION, + PROP_TOOLBAR_STYLE, + PROP_SHOW_ARROW +}; + +enum { + ORIENTATION_CHANGED, + STYLE_CHANGED, + LAST_SIGNAL +}; + +static void egg_toolbar_init (EggToolbar *toolbar); +static void egg_toolbar_class_init (EggToolbarClass *klass); + +static void egg_toolbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void egg_toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static gint egg_toolbar_expose (GtkWidget *widget, + GdkEventExpose *event); +static void egg_toolbar_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void egg_toolbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static void egg_toolbar_style_set (GtkWidget *widget, + GtkStyle *prev_style); +static gboolean egg_toolbar_focus (GtkWidget *widget, + GtkDirectionType dir); +static void egg_toolbar_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen); + +static void egg_toolbar_add (GtkContainer *container, + GtkWidget *widget); +static void egg_toolbar_remove (GtkContainer *container, + GtkWidget *widget); +static void egg_toolbar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static GType egg_toolbar_child_type (GtkContainer *container); + + +static void egg_toolbar_real_orientation_changed (EggToolbar *toolbar, + GtkOrientation orientation); +static void egg_toolbar_real_style_changed (EggToolbar *toolbar, + GtkToolbarStyle style); + +static void egg_toolbar_button_press (GtkWidget *button, + GdkEventButton *event, + EggToolbar *toolbar); +static void egg_toolbar_update_button_relief (EggToolbar *toolbar); +static GtkReliefStyle get_button_relief (EggToolbar *toolbar); +static gint get_space_size (EggToolbar *toolbar); +static GtkToolbarSpaceStyle get_space_style (EggToolbar *toolbar); + +static GtkWidget *egg_toolbar_internal_insert_element (EggToolbar *toolbar, + EggToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position, + gboolean use_stock); + + +#define PRIVATE_KEY "egg-toolbar-private" + +#define EGG_TOOLBAR_GET_PRIVATE(toolbar) (g_object_get_data (G_OBJECT (toolbar), PRIVATE_KEY)) + +typedef struct +{ + GList *items; + GList *first_non_fitting_item; + + gint total_button_maxw; + gint total_button_maxh; + + GtkWidget *button; + GtkWidget *arrow; + + gboolean show_arrow; +} EggToolbarPrivate; + +static GtkContainerClass *parent_class = NULL; +static guint toolbar_signals [LAST_SIGNAL] = { 0 }; + +GType +egg_toolbar_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggToolbarClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_toolbar_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EggToolbar), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_toolbar_init, + }; + + type = g_type_register_static (GTK_TYPE_CONTAINER, + "EggToolbar", + &type_info, 0); + } + + return type; +} + +static void +egg_toolbar_class_init (EggToolbarClass *klass) +{ + GObjectClass *gobject_class; + GtkWidgetClass *widget_class; + GtkContainerClass *container_class; + + gobject_class = (GObjectClass *)klass; + widget_class = (GtkWidgetClass *)klass; + container_class = (GtkContainerClass *)klass; + + gobject_class->set_property = egg_toolbar_set_property; + gobject_class->get_property = egg_toolbar_get_property; + + widget_class->expose_event = egg_toolbar_expose; + widget_class->size_request = egg_toolbar_size_request; + widget_class->size_allocate = egg_toolbar_size_allocate; + widget_class->style_set = egg_toolbar_style_set; + widget_class->focus = egg_toolbar_focus; + widget_class->screen_changed = egg_toolbar_screen_changed; + + container_class->add = egg_toolbar_add; + container_class->remove = egg_toolbar_remove; + container_class->forall = egg_toolbar_forall; + container_class->child_type = egg_toolbar_child_type; + + klass->orientation_changed = egg_toolbar_real_orientation_changed; + klass->style_changed = egg_toolbar_real_style_changed; + + toolbar_signals[ORIENTATION_CHANGED] = + g_signal_new ("orientation_changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EggToolbarClass, orientation_changed), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_ORIENTATION); + toolbar_signals[STYLE_CHANGED] = + g_signal_new ("style_changed", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EggToolbarClass, style_changed), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_TOOLBAR_STYLE); + + g_object_class_install_property (gobject_class, + PROP_ORIENTATION, + g_param_spec_enum ("orientation", + _("Orientation"), + _("The orientation of the toolbar"), + GTK_TYPE_ORIENTATION, + GTK_ORIENTATION_HORIZONTAL, + G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, + PROP_TOOLBAR_STYLE, + g_param_spec_enum ("toolbar_style", + _("Toolbar Style"), + _("How to draw the toolbar"), + GTK_TYPE_TOOLBAR_STYLE, + GTK_TOOLBAR_ICONS, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_SHOW_ARROW, + g_param_spec_boolean ("show_arrow", + _("Show Arrow"), + _("If an arrow should be shown if the toolbar doesn't fit"), + FALSE, + G_PARAM_READWRITE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("space_size", + _("Spacer size"), + _("Size of spacers"), + 0, + G_MAXINT, + DEFAULT_SPACE_SIZE, + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_int ("internal_padding", + _("Internal padding"), + _("Amount of border space between the toolbar shadow and the buttons"), + 0, + G_MAXINT, + DEFAULT_IPADDING, + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_enum ("space_style", + _("Space style"), + _("Whether spacers are vertical lines or just blank"), + GTK_TYPE_TOOLBAR_SPACE_STYLE, + DEFAULT_SPACE_STYLE, + G_PARAM_READABLE)); + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_enum ("button_relief", + _("Button relief"), + _("Type of bevel around toolbar buttons"), + GTK_TYPE_RELIEF_STYLE, + GTK_RELIEF_NONE, + G_PARAM_READABLE)); + gtk_widget_class_install_style_property (widget_class, + g_param_spec_enum ("shadow_type", + _("Shadow type"), + _("Style of bevel around the toolbar"), + GTK_TYPE_SHADOW_TYPE, + GTK_SHADOW_OUT, + G_PARAM_READABLE)); + + gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-style", + _("Toolbar style"), + _("Whether default toolbars have text only, text and icons, icons only, etc."), + GTK_TYPE_TOOLBAR_STYLE, + DEFAULT_TOOLBAR_STYLE, + G_PARAM_READWRITE)); + + gtk_settings_install_property (g_param_spec_enum ("gtk-toolbar-icon-size", + _("Toolbar icon size"), + _("Size of icons in default toolbars"), + GTK_TYPE_ICON_SIZE, + DEFAULT_ICON_SIZE, + G_PARAM_READWRITE)); +} + +static void +egg_toolbar_init (EggToolbar *toolbar) +{ + EggToolbarPrivate *priv; + + GTK_WIDGET_SET_FLAGS (toolbar, GTK_NO_WINDOW); + GTK_WIDGET_UNSET_FLAGS (toolbar, GTK_CAN_FOCUS); + + priv = g_new0 (EggToolbarPrivate, 1); + g_object_set_data (G_OBJECT (toolbar), PRIVATE_KEY, priv); + + toolbar->orientation = GTK_ORIENTATION_HORIZONTAL; + toolbar->style = GTK_TOOLBAR_ICONS; + toolbar->tooltips = gtk_tooltips_new (); + g_object_ref (toolbar->tooltips); + gtk_object_sink (GTK_OBJECT (toolbar->tooltips)); + + priv->button = gtk_toggle_button_new (); + g_signal_connect (priv->button, "button_press_event", + G_CALLBACK (egg_toolbar_button_press), toolbar); + gtk_button_set_relief (GTK_BUTTON (priv->button), + get_button_relief (toolbar)); + GTK_WIDGET_UNSET_FLAGS (priv->button, GTK_CAN_FOCUS); + + priv->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE); + gtk_widget_show (priv->arrow); + gtk_container_add (GTK_CONTAINER (priv->button), priv->arrow); + + gtk_widget_set_parent (priv->button, GTK_WIDGET (toolbar)); +} + +static void +egg_toolbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EggToolbar *toolbar = EGG_TOOLBAR (object); + + switch (prop_id) + { + case PROP_ORIENTATION: + egg_toolbar_set_orientation (toolbar, g_value_get_enum (value)); + break; + case PROP_TOOLBAR_STYLE: + egg_toolbar_set_style (toolbar, g_value_get_enum (value)); + break; + case PROP_SHOW_ARROW: + egg_toolbar_set_show_arrow (toolbar, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +egg_toolbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EggToolbar *toolbar = EGG_TOOLBAR (object); + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + switch (prop_id) + { + case PROP_ORIENTATION: + g_value_set_enum (value, toolbar->orientation); + break; + case PROP_TOOLBAR_STYLE: + g_value_set_enum (value, toolbar->style); + break; + case PROP_SHOW_ARROW: + g_value_set_boolean (value, priv->show_arrow); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +egg_toolbar_paint_space_line (GtkWidget *widget, + GdkRectangle *area, + EggToolItem *item) +{ + EggToolbar *toolbar; + GtkAllocation *allocation; + gint space_size; + + g_return_if_fail (GTK_BIN (item)->child == NULL); + + toolbar = EGG_TOOLBAR (widget); + + allocation = >K_WIDGET (item)->allocation; + space_size = get_space_size (toolbar); + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_paint_vline (widget->style, widget->window, + GTK_WIDGET_STATE (widget), area, widget, + "toolbar", + allocation->y + allocation->height * + SPACE_LINE_START / SPACE_LINE_DIVISION, + allocation->y + allocation->height * + SPACE_LINE_END / SPACE_LINE_DIVISION, + allocation->x + (space_size-widget->style->xthickness)/2); + else if (toolbar->orientation == GTK_ORIENTATION_VERTICAL) + gtk_paint_hline (widget->style, widget->window, + GTK_WIDGET_STATE (widget), area, widget, + "toolbar", + allocation->x + allocation->width * + SPACE_LINE_START / SPACE_LINE_DIVISION, + allocation->x + allocation->width * + SPACE_LINE_END / SPACE_LINE_DIVISION, + allocation->y + (space_size-widget->style->ythickness)/2); +} + +static gint +egg_toolbar_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + EggToolbar *toolbar = EGG_TOOLBAR (widget); + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + GList *items; + gint border_width; + + border_width = GTK_CONTAINER (widget)->border_width; + + if (GTK_WIDGET_DRAWABLE (widget)) + { + GtkShadowType shadow_type; + + gtk_widget_style_get (widget, "shadow_type", &shadow_type, NULL); + + gtk_paint_box (widget->style, + widget->window, + GTK_WIDGET_STATE (widget), + shadow_type, + &event->area, widget, "toolbar", + widget->allocation.x + border_width, + widget->allocation.y + border_width, + widget->allocation.width - border_width, + widget->allocation.height - border_width); + + } + + items = priv->items; + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + if (GTK_BIN (item)->child) + gtk_container_propagate_expose (GTK_CONTAINER (widget), + GTK_WIDGET (item), + event); + else if (GTK_WIDGET_MAPPED (item) && get_space_style (toolbar) == GTK_TOOLBAR_SPACE_LINE) + egg_toolbar_paint_space_line (widget, &event->area, item); + + items = items->next; + } + + gtk_container_propagate_expose (GTK_CONTAINER (widget), + priv->button, + event); + + return FALSE; +} + +static void +egg_toolbar_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + EggToolbar *toolbar = EGG_TOOLBAR (widget); + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + GList *items; + gint nbuttons, ipadding; + gint button_maxw, button_maxh; + gint total_button_maxw, total_button_maxh; + gint space_size; + GtkRequisition child_requisition; + + requisition->width = GTK_CONTAINER (toolbar)->border_width * 2; + requisition->height = GTK_CONTAINER (toolbar)->border_width * 2; + nbuttons = 0; + button_maxw = 0; + button_maxh = 0; + total_button_maxw = 0; + total_button_maxh = 0; + items = priv->items; + space_size = get_space_size (toolbar); + + if (priv->show_arrow) + { + /* When we enable the arrow we only want to be the + * size of the arrows plus the size of any items that + * are pack-end. + */ + + items = priv->items; + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + if (TOOLBAR_ITEM_VISIBLE (item)) + { + gtk_widget_size_request (GTK_WIDGET (item), &child_requisition); + + total_button_maxw = MAX (total_button_maxw, child_requisition.width); + total_button_maxh = MAX (total_button_maxh, child_requisition.height); + + if (item->homogeneous) + { + if (item->pack_end) + nbuttons++; + button_maxw = MAX (button_maxw, child_requisition.width); + button_maxh = MAX (button_maxh, child_requisition.height); + } + else if (item->pack_end) + { + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + requisition->width += child_requisition.width; + else + requisition->height += child_requisition.height; + } + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + requisition->height = MAX (requisition->height, child_requisition.height); + else + requisition->width = MAX (requisition->width, child_requisition.width); + } + + items = items->next; + } + + /* Add the arrow */ + gtk_widget_size_request (priv->button, &child_requisition); + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + requisition->width += child_requisition.width; + requisition->height = MAX (requisition->height, child_requisition.height); + } + else + { + requisition->height += child_requisition.height; + requisition->width = MAX (requisition->width, child_requisition.width); + } + } + else + { + items = priv->items; + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + if (!TOOLBAR_ITEM_VISIBLE (item)) + { + items = items->next; + continue; + } + + if (!GTK_BIN (item)->child) + { + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + requisition->width += space_size; + else + requisition->height += space_size; + } + else + { + gtk_widget_size_request (GTK_WIDGET (item), &child_requisition); + + total_button_maxw = MAX (total_button_maxw, child_requisition.width); + total_button_maxh = MAX (total_button_maxh, child_requisition.height); + + if (item->homogeneous) + { + nbuttons++; + button_maxw = MAX (button_maxw, child_requisition.width); + button_maxh = MAX (button_maxh, child_requisition.height); + } + else + { + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + requisition->width += child_requisition.width; + requisition->height = MAX (requisition->height, child_requisition.height); + } + else + { + requisition->height += child_requisition.height; + requisition->width = MAX (requisition->width, child_requisition.width); + } + } + } + + items = items->next; + } + } + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + requisition->width += nbuttons * button_maxw; + requisition->height = MAX (requisition->height, button_maxh); + } + else + { + requisition->width = MAX (requisition->width, button_maxw); + requisition->height += nbuttons * button_maxh; + } + + /* Extra spacing */ + gtk_widget_style_get (widget, "internal_padding", &ipadding, NULL); + + requisition->width += 2 * ipadding; + requisition->height += 2 * ipadding; + + priv->total_button_maxw = total_button_maxw; + priv->total_button_maxh = total_button_maxh; + + toolbar->button_maxw = button_maxw; + toolbar->button_maxh = button_maxh; +} + +static void +egg_toolbar_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + EggToolbar *toolbar = EGG_TOOLBAR (widget); + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + GList *items; + GtkAllocation child_allocation; + gint ipadding, space_size; + gint border_width, edge_position; + gint available_width, available_height; + gint available_size, total_size; + GtkRequisition child_requisition; + gint remaining_size; + gint number_expandable, expandable_size; + gboolean first_expandable; + + widget->allocation = *allocation; + border_width = GTK_CONTAINER (widget)->border_width; + total_size = 0; + number_expandable = 0; + space_size = get_space_size (toolbar); + + gtk_widget_style_get (widget, "internal_padding", &ipadding, NULL); + border_width += ipadding; + + available_width = allocation->width - 2 * border_width; + available_height = allocation->height - 2 * border_width; + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + edge_position = allocation->x + allocation->width - border_width; + available_size = available_width; + } + else + { + edge_position = allocation->y + allocation->height - border_width; + available_size = available_height; + } + + items = g_list_last (priv->items); + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + if (!item->pack_end || !TOOLBAR_ITEM_VISIBLE (item)) + { + items = items->prev; + continue; + } + + if (!GTK_BIN (item)->child) + { + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + child_allocation.width = space_size; + child_allocation.height = available_height; + child_allocation.x = edge_position - child_allocation.width; + child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2; + + gtk_widget_size_allocate (GTK_WIDGET (item), &child_allocation); + + edge_position -= child_allocation.width; + available_size -= child_allocation.width; + } + else + { + child_allocation.width = available_width; + child_allocation.height = space_size; + child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2; + child_allocation.y = edge_position - child_allocation.height; + + gtk_widget_size_allocate (GTK_WIDGET (item), &child_allocation); + + edge_position -= child_allocation.height; + available_size -= child_allocation.height; + } + } + else + { + gtk_widget_get_child_requisition (GTK_WIDGET (item), &child_requisition); + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (item->homogeneous) + child_allocation.width = toolbar->button_maxw; + else + child_allocation.width = child_requisition.width; + child_allocation.height = available_height; + child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2; + child_allocation.x = edge_position - child_allocation.width; + + gtk_widget_size_allocate (GTK_WIDGET (item), &child_allocation); + + edge_position -= child_allocation.width; + available_size -= child_allocation.width; + } + else + { + if (item->homogeneous) + child_allocation.height = toolbar->button_maxh; + else + child_allocation.height = child_requisition.height; + + child_allocation.width = available_width; + child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2; + child_allocation.y = edge_position - child_allocation.height; + + gtk_widget_size_allocate (GTK_WIDGET (item), &child_allocation); + + edge_position -= child_allocation.height; + available_size -= child_allocation.height; + } + } + + items = items->prev; + } + + /* Now go through the items and see if they fit */ + items = priv->items; + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + if (item->pack_end || !TOOLBAR_ITEM_VISIBLE (item)) + { + items = items->next; + continue; + } + + if (item->expandable) + number_expandable += 1; + + if (!GTK_BIN (item)->child) + { + total_size += space_size; + } + else + { + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_widget_get_child_requisition (GTK_WIDGET (item), &child_requisition); + + if (item->homogeneous) + total_size += toolbar->button_maxw; + else + total_size += child_requisition.width; + } + else + { + gtk_widget_get_child_requisition (GTK_WIDGET (item), &child_requisition); + + if (item->homogeneous) + total_size += toolbar->button_maxh; + else + total_size += child_requisition.height; + } + } + items = items->next; + } + + /* Check if we need to allocate and show the arrow */ + if (available_size < total_size) + { + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + gtk_widget_get_child_requisition (priv->button, &child_requisition); + available_size -= child_requisition.width; + + child_allocation.width = child_requisition.width; + child_allocation.height = priv->total_button_maxh; + child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2; + child_allocation.x = edge_position - child_allocation.width; + } + else + { + gtk_widget_get_child_requisition (priv->button, &child_requisition); + available_size -= child_requisition.width; + + child_allocation.height = child_requisition.height; + child_allocation.width = priv->total_button_maxw; + child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2; + child_allocation.y = edge_position - child_allocation.height; + } + + gtk_widget_size_allocate (priv->button, &child_allocation); + gtk_widget_show (priv->button); + } + else + gtk_widget_hide (priv->button); + + /* Finally allocate the remaining items */ + items = priv->items; + child_allocation.x = allocation->x + border_width; + child_allocation.y = allocation->y + border_width; + remaining_size = MAX (0, available_size - total_size); + total_size = 0; + first_expandable = TRUE; + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + if (item->pack_end || !TOOLBAR_ITEM_VISIBLE (item)) + { + items = items->next; + continue; + } + + if (!GTK_BIN (item)->child) + { + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + child_allocation.width = space_size; + child_allocation.height = available_height; + child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2; + total_size += child_allocation.width; + + if (total_size > available_size) + break; + + gtk_widget_size_allocate (GTK_WIDGET (item), &child_allocation); + gtk_widget_map (GTK_WIDGET (item)); + + child_allocation.x += child_allocation.width; + } + else + { + child_allocation.width = available_width; + child_allocation.height = space_size; + child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2; + total_size += child_allocation.height; + + if (total_size > available_size) + break; + + gtk_widget_size_allocate (GTK_WIDGET (item), &child_allocation); + gtk_widget_map (GTK_WIDGET (item)); + + child_allocation.y += child_allocation.height; + } + } + else + { + gtk_widget_get_child_requisition (GTK_WIDGET (item), &child_requisition); + + if (item->expandable) + { + expandable_size = remaining_size / number_expandable; + + if (first_expandable) + { + expandable_size += remaining_size % number_expandable; + first_expandable = FALSE; + } + } + else + expandable_size = 0; + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + if (item->homogeneous) + child_allocation.width = toolbar->button_maxw; + else + child_allocation.width = child_requisition.width; + + child_allocation.height = available_height; + child_allocation.width += expandable_size; + child_allocation.y = allocation->y + (allocation->height - child_allocation.height) / 2; + total_size += child_allocation.width; + } + else + { + if (item->homogeneous) + child_allocation.height = toolbar->button_maxh; + else + child_allocation.height = child_requisition.height; + + child_allocation.width = available_width; + child_allocation.height += expandable_size; + child_allocation.x = allocation->x + (allocation->width - child_allocation.width) / 2; + total_size += child_allocation.height; + } + + if (total_size > available_size) + break; + + gtk_widget_size_allocate (GTK_WIDGET (item), &child_allocation); + gtk_widget_map (GTK_WIDGET (item)); + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + child_allocation.x += child_allocation.width; + else + child_allocation.y += child_allocation.height; + + } + + items = items->next; + } + + /* Unmap the remaining items */ + priv->first_non_fitting_item = items; + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + gtk_widget_unmap (GTK_WIDGET (item)); + items = items->next; + } +} + +static void +egg_toolbar_style_set (GtkWidget *widget, + GtkStyle *prev_style) +{ + if (prev_style) + egg_toolbar_update_button_relief (EGG_TOOLBAR (widget)); +} + +static gboolean +egg_toolbar_focus (GtkWidget *widget, + GtkDirectionType dir) +{ + /* Focus can't go in toolbars */ + + return FALSE; +} + +static void +style_change_notify (EggToolbar *toolbar) +{ + if (!toolbar->style_set) + { + /* pretend it was set, then unset, thus reverting to new default */ + toolbar->style_set = TRUE; + egg_toolbar_unset_style (toolbar); + } +} + +static void +icon_size_change_notify (EggToolbar *toolbar) +{ + if (!toolbar->icon_size_set) + { + /* pretend it was set, then unset, thus reverting to new default */ + toolbar->icon_size_set = TRUE; + egg_toolbar_unset_icon_size (toolbar); + } +} + +static GtkSettings * +toolbar_get_settings (EggToolbar *toolbar) +{ + return g_object_get_data (G_OBJECT (toolbar), "egg-toolbar-settings"); +} + +static void +egg_toolbar_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen) +{ + EggToolbar *toolbar = EGG_TOOLBAR (widget); + GtkSettings *old_settings = toolbar_get_settings (toolbar); + GtkSettings *settings; + + if (gtk_widget_has_screen (GTK_WIDGET (toolbar))) + settings = gtk_widget_get_settings (GTK_WIDGET (toolbar)); + else + settings = NULL; + + if (settings == old_settings) + return; + + if (old_settings) + { + g_signal_handler_disconnect (old_settings, toolbar->style_set_connection); + g_signal_handler_disconnect (old_settings, toolbar->icon_size_connection); + + g_object_unref (old_settings); + } + + if (settings) + { + toolbar->style_set_connection = + g_signal_connect_swapped (settings, + "notify::gtk-toolbar-style", + G_CALLBACK (style_change_notify), + toolbar); + toolbar->icon_size_connection = + g_signal_connect_swapped (settings, + "notify::gtk-toolbar-icon-size", + G_CALLBACK (icon_size_change_notify), + toolbar); + + g_object_ref (settings); + g_object_set_data (G_OBJECT (toolbar), "egg-toolbar-settings", settings); + } + else + g_object_set_data (G_OBJECT (toolbar), "egg-toolbar-settings", NULL); + + style_change_notify (toolbar); + icon_size_change_notify (toolbar); +} + + +static void +egg_toolbar_add (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (EGG_IS_TOOLBAR (container)); + g_return_if_fail (EGG_IS_TOOL_ITEM (widget)); + + egg_toolbar_append_tool_item (EGG_TOOLBAR (container), + EGG_TOOL_ITEM (widget)); +} + +static void +egg_toolbar_remove (GtkContainer *container, + GtkWidget *widget) +{ + g_return_if_fail (EGG_IS_TOOLBAR (container)); + g_return_if_fail (EGG_IS_TOOL_ITEM (widget)); + + egg_toolbar_remove_tool_item (EGG_TOOLBAR (container), + EGG_TOOL_ITEM (widget)); +} + +static void +egg_toolbar_forall (GtkContainer *container, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data) +{ + EggToolbar *toolbar = EGG_TOOLBAR (container); + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + GList *items; + + g_return_if_fail (callback != NULL); + + items = priv->items; + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + items = items->next; + (*callback) (GTK_WIDGET (item), callback_data); + } + + if (include_internals) + (* callback) (priv->button, callback_data); +} + +static GType +egg_toolbar_child_type (GtkContainer *container) +{ + return EGG_TYPE_TOOL_ITEM; +} + +static void +egg_toolbar_real_orientation_changed (EggToolbar *toolbar, + GtkOrientation orientation) +{ + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + GList *items; + + if (toolbar->orientation != orientation) + { + toolbar->orientation = orientation; + + items = priv->items; + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + egg_tool_item_set_orientation (item, orientation); + + items = items->next; + } + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE); + else + gtk_arrow_set (GTK_ARROW (priv->arrow), GTK_ARROW_RIGHT, GTK_SHADOW_NONE); + + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); + g_object_notify (G_OBJECT (toolbar), "orientation"); + } +} + +static void +egg_toolbar_real_style_changed (EggToolbar *toolbar, + GtkToolbarStyle style) +{ + EggToolbarPrivate *priv; + GList *items; + + priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + if (toolbar->style != style) + { + toolbar->style = style; + + items = priv->items; + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + egg_tool_item_set_toolbar_style (item, style); + + items = items->next; + } + + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); + g_object_notify (G_OBJECT (toolbar), "toolbar_style"); + } +} + +static void +menu_position_func (GtkMenu *menu, + gint *x, + gint *y, + gboolean *push_in, + gpointer user_data) +{ + EggToolbar *toolbar = EGG_TOOLBAR (user_data); + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + GtkRequisition req; + + gdk_window_get_origin (GTK_BUTTON (priv->button)->event_window, x, y); + gtk_widget_size_request (priv->button, &req); + + if (toolbar->orientation == GTK_ORIENTATION_HORIZONTAL) + { + *y += priv->button->allocation.height; + *x += priv->button->allocation.width - req.width; + } + else + { + *x += priv->button->allocation.width; + *y += priv->button->allocation.height - req.height; + } + + *push_in = TRUE; +} + +static void +menu_deactivated (GtkWidget *menu, GtkWidget *button) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), FALSE); +} + +static void +egg_toolbar_button_press (GtkWidget *button, + GdkEventButton *event, + EggToolbar *toolbar) +{ + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + GtkWidget *menu; + GtkWidget *menu_item; + GList *items; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE); + + menu = gtk_menu_new (); + g_signal_connect (menu, "deactivate", G_CALLBACK (menu_deactivated), button); + + items = priv->first_non_fitting_item; + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + if (TOOLBAR_ITEM_VISIBLE (item) && !item->pack_end) + { + menu_item = NULL; + g_signal_emit_by_name (item, "create_menu_proxy", &menu_item); + + if (menu_item) + { + gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item); + } + } + items = items->next; + } + + gtk_widget_show_all (menu); + + gtk_menu_popup (GTK_MENU (menu), NULL, NULL, + menu_position_func, toolbar, + event->button, event->time); +} + +static void +egg_toolbar_update_button_relief (EggToolbar *toolbar) +{ + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + GtkReliefStyle relief; + GList *items; + + relief = get_button_relief (toolbar); + + items = priv->items; + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + egg_tool_item_set_relief_style (item, relief); + + items = items->next; + } + + gtk_button_set_relief (GTK_BUTTON (priv->button), relief); +} + +static GtkReliefStyle +get_button_relief (EggToolbar *toolbar) +{ + GtkReliefStyle button_relief = GTK_RELIEF_NORMAL; + + gtk_widget_ensure_style (GTK_WIDGET (toolbar)); + + gtk_widget_style_get (GTK_WIDGET (toolbar), + "button_relief", &button_relief, + NULL); + + return button_relief; +} + +static gint +get_space_size (EggToolbar *toolbar) +{ + gint space_size = DEFAULT_SPACE_SIZE; + + gtk_widget_style_get (GTK_WIDGET (toolbar), + "space_size", &space_size, + NULL); + + return space_size; +} + +static GtkToolbarSpaceStyle +get_space_style (EggToolbar *toolbar) +{ + GtkToolbarSpaceStyle space_style = DEFAULT_SPACE_STYLE; + + gtk_widget_style_get (GTK_WIDGET (toolbar), + "space_style", &space_style, + NULL); + + + return space_style; +} + +GtkWidget * +egg_toolbar_new (void) +{ + EggToolbar *toolbar; + + toolbar = g_object_new (EGG_TYPE_TOOLBAR, NULL); + + return GTK_WIDGET (toolbar); +} + +void +egg_toolbar_append_tool_item (EggToolbar *toolbar, + EggToolItem *item) +{ + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + g_return_if_fail (EGG_IS_TOOL_ITEM (item)); + + egg_toolbar_insert_tool_item (toolbar, item, toolbar->num_children); +} + +void +egg_toolbar_prepend_tool_item (EggToolbar *toolbar, + EggToolItem *item) +{ + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + g_return_if_fail (EGG_IS_TOOL_ITEM (item)); + + egg_toolbar_insert_tool_item (toolbar, item, 0); +} + +void +egg_toolbar_remove_tool_item (EggToolbar *toolbar, + EggToolItem *item) +{ + EggToolbarPrivate *priv; + GList *tmp; + + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + g_return_if_fail (EGG_IS_TOOL_ITEM (item)); + + priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + for (tmp = priv->items; tmp != NULL; tmp = tmp->next) + { + GtkWidget *child = tmp->data; + + if (child == GTK_WIDGET (item)) + { + gboolean was_visible; + + was_visible = GTK_WIDGET_VISIBLE (item); + gtk_widget_unparent (GTK_WIDGET (item)); + + priv->items = g_list_remove_link (priv->items, tmp); + toolbar->num_children--; + + if (was_visible && GTK_WIDGET_VISIBLE (toolbar)) + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); + + break; + } + } +} + +void +egg_toolbar_insert_tool_item (EggToolbar *toolbar, + EggToolItem *item, + gint pos) +{ + EggToolbarPrivate *priv; + + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + g_return_if_fail (EGG_IS_TOOL_ITEM (item)); + + priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + priv->items = g_list_insert (priv->items, item, pos); + toolbar->num_children++; + + egg_tool_item_set_orientation (item, toolbar->orientation); + egg_tool_item_set_toolbar_style (item, toolbar->style); + egg_tool_item_set_relief_style (item, get_button_relief (toolbar)); + + gtk_widget_set_parent (GTK_WIDGET (item), GTK_WIDGET (toolbar)); + GTK_WIDGET_UNSET_FLAGS (item, GTK_CAN_FOCUS); +} + +void +egg_toolbar_set_orientation (EggToolbar *toolbar, + GtkOrientation orientation) +{ + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + + g_signal_emit (toolbar, toolbar_signals[ORIENTATION_CHANGED], 0, orientation); +} + +GtkOrientation +egg_toolbar_get_orientation (EggToolbar *toolbar) +{ + g_return_val_if_fail (EGG_IS_TOOLBAR (toolbar), GTK_ORIENTATION_HORIZONTAL); + + return toolbar->orientation; +} + +void +egg_toolbar_set_style (EggToolbar *toolbar, + GtkToolbarStyle style) +{ + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + + toolbar->style_set = TRUE; + g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style); +} + +GtkToolbarStyle +egg_toolbar_get_style (EggToolbar *toolbar) +{ + g_return_val_if_fail (EGG_IS_TOOLBAR (toolbar), DEFAULT_TOOLBAR_STYLE); + + return toolbar->style; +} + +void +egg_toolbar_unset_style (EggToolbar *toolbar) +{ + GtkToolbarStyle style; + + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + + if (toolbar->style_set) + { + GtkSettings *settings = toolbar_get_settings (toolbar); + + if (settings) + g_object_get (settings, + "gtk-toolbar-style", &style, + NULL); + else + style = DEFAULT_TOOLBAR_STYLE; + + if (style != toolbar->style) + g_signal_emit (toolbar, toolbar_signals[STYLE_CHANGED], 0, style); + + toolbar->style_set = FALSE; + } +} + +void +egg_toolbar_set_tooltips (EggToolbar *toolbar, + gboolean enable) +{ + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + + if (enable) + gtk_tooltips_enable (toolbar->tooltips); + else + gtk_tooltips_disable (toolbar->tooltips); +} + +gboolean +egg_toolbar_get_tooltips (EggToolbar *toolbar) +{ + g_return_val_if_fail (EGG_IS_TOOLBAR (toolbar), FALSE); + + return toolbar->tooltips->enabled; +} + +GList* +egg_toolbar_get_tool_items (EggToolbar *toolbar) +{ + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + g_return_val_if_fail (EGG_IS_TOOLBAR (toolbar), FALSE); + + return priv->items; +} + +void +egg_toolbar_set_icon_size (EggToolbar *toolbar, + GtkIconSize icon_size) +{ + GList *items; + EggToolbarPrivate *priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + + toolbar->icon_size_set = TRUE; + + if (toolbar->icon_size == icon_size) + return; + + toolbar->icon_size = icon_size; + + items = priv->items; + + while (items) + { + EggToolItem *item = EGG_TOOL_ITEM (items->data); + + egg_tool_item_set_icon_size (item, icon_size); + + items = items->next; + } + + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); +} + +GtkIconSize +egg_toolbar_get_icon_size (EggToolbar *toolbar) +{ + g_return_val_if_fail (EGG_IS_TOOLBAR (toolbar), DEFAULT_ICON_SIZE); + + return toolbar->icon_size; +} + +void +egg_toolbar_unset_icon_size (EggToolbar *toolbar) +{ + GtkIconSize size; + + if (toolbar->icon_size_set) + { + GtkSettings *settings = toolbar_get_settings (toolbar); + + if (settings) + g_object_get (settings, + "gtk-toolbar-icon-size", &size, + NULL); + else + size = DEFAULT_ICON_SIZE; + + if (size != toolbar->icon_size) + egg_toolbar_set_icon_size (toolbar, size); + + toolbar->icon_size_set = FALSE; + } +} + + +void +egg_toolbar_set_show_arrow (EggToolbar *toolbar, + gboolean show_arrow) +{ + EggToolbarPrivate *priv; + + g_return_if_fail (EGG_IS_TOOLBAR (toolbar)); + + priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + show_arrow = show_arrow != FALSE; + + if (priv->show_arrow != show_arrow) + { + priv->show_arrow = show_arrow; + + if (!priv->show_arrow) + gtk_widget_hide (priv->button); + + gtk_widget_queue_resize (GTK_WIDGET (toolbar)); + g_object_notify (G_OBJECT (toolbar), "show_arrow"); + } +} + +gboolean +egg_toolbar_get_show_arrow (EggToolbar *toolbar) +{ + EggToolbarPrivate *priv; + + g_return_val_if_fail (EGG_IS_TOOLBAR (toolbar), FALSE); + + priv = EGG_TOOLBAR_GET_PRIVATE (toolbar); + + return priv->show_arrow; +} + +GtkWidget * +egg_toolbar_append_item (EggToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data) +{ + return egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_BUTTON, + NULL, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, + toolbar->num_children); +} + +GtkWidget * +egg_toolbar_prepend_item (EggToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data) +{ + return egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_BUTTON, + NULL, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, + 0); +} + +GtkWidget * +egg_toolbar_insert_item (EggToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position) +{ + return egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_BUTTON, + NULL, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, + position); +} + +GtkWidget* +egg_toolbar_insert_stock (EggToolbar *toolbar, + const gchar *stock_id, + const char *tooltip_text, + const char *tooltip_private_text, + GtkSignalFunc callback, + gpointer user_data, + gint position) +{ + return egg_toolbar_internal_insert_element (toolbar, EGG_TOOLBAR_CHILD_BUTTON, + NULL, stock_id, + tooltip_text, tooltip_private_text, + NULL, callback, user_data, + position, TRUE); +} + +void +egg_toolbar_append_space (EggToolbar *toolbar) +{ + egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_SPACE, + NULL, NULL, + NULL, NULL, + NULL, NULL, NULL, + toolbar->num_children); +} + +void +egg_toolbar_prepend_space (EggToolbar *toolbar) +{ + egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_SPACE, + NULL, NULL, + NULL, NULL, + NULL, NULL, NULL, + 0); +} + +void +egg_toolbar_insert_space (EggToolbar *toolbar, + gint position) +{ + egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_SPACE, + NULL, NULL, + NULL, NULL, + NULL, NULL, NULL, + position); +} + +void +egg_toolbar_append_widget (EggToolbar *toolbar, + GtkWidget *widget, + const gchar *tooltip_text, + const gchar *tooltip_private_text) +{ + egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_WIDGET, + widget, NULL, + tooltip_text, tooltip_private_text, + NULL, NULL, NULL, + toolbar->num_children); +} + +void +egg_toolbar_prepend_widget (EggToolbar *toolbar, + GtkWidget *widget, + const gchar *tooltip_text, + const gchar *tooltip_private_text) +{ + egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_WIDGET, + widget, NULL, + tooltip_text, tooltip_private_text, + NULL, NULL, NULL, + 0); +} + +void +egg_toolbar_insert_widget (EggToolbar *toolbar, + GtkWidget *widget, + const char *tooltip_text, + const char *tooltip_private_text, + gint position) +{ + egg_toolbar_insert_element (toolbar, EGG_TOOLBAR_CHILD_WIDGET, + widget, NULL, + tooltip_text, tooltip_private_text, + NULL, NULL, NULL, + position); +} + +GtkWidget* +egg_toolbar_append_element (EggToolbar *toolbar, + GtkToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data) +{ + return egg_toolbar_insert_element (toolbar, type, widget, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, + toolbar->num_children); +} + +GtkWidget * +egg_toolbar_prepend_element (EggToolbar *toolbar, + GtkToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data) +{ + return egg_toolbar_insert_element (toolbar, type, widget, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, 0); +} + +GtkWidget * +egg_toolbar_insert_element (EggToolbar *toolbar, + EggToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position) +{ + return egg_toolbar_internal_insert_element (toolbar, type, widget, text, + tooltip_text, tooltip_private_text, + icon, callback, user_data, position, FALSE); +} + +static GtkWidget * +egg_toolbar_internal_insert_element (EggToolbar *toolbar, + EggToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position, + gboolean use_stock) +{ + EggToolbarChild *child; + EggToolItem *item = NULL; + + g_return_val_if_fail (EGG_IS_TOOLBAR (toolbar), NULL); + + if (type == EGG_TOOLBAR_CHILD_WIDGET) + g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL); + else if (type != EGG_TOOLBAR_CHILD_RADIOBUTTON) + g_return_val_if_fail (widget == NULL, NULL); + + child = g_new (EggToolbarChild, 1); + + child->type = type; + child->icon = NULL; + child->label = NULL; + + switch (type) + { + case EGG_TOOLBAR_CHILD_SPACE: + item = egg_separator_tool_item_new (); + child->widget = NULL; + break; + + case EGG_TOOLBAR_CHILD_WIDGET: + item = egg_tool_item_new (); + child->widget = widget; + gtk_container_add (GTK_CONTAINER (item), child->widget); + + break; + + case EGG_TOOLBAR_CHILD_BUTTON: + item = egg_tool_button_new (); + child->widget = EGG_TOOL_BUTTON (item)->button; + break; + + case EGG_TOOLBAR_CHILD_TOGGLEBUTTON: + item = egg_toggle_tool_button_new (); + child->widget = EGG_TOOL_BUTTON (item)->button; + break; + + case EGG_TOOLBAR_CHILD_RADIOBUTTON: + item = egg_radio_tool_button_new (widget + ? gtk_radio_button_get_group (GTK_RADIO_BUTTON (widget)) + : NULL); + child->widget = EGG_TOOL_BUTTON (item)->button; + break; + } + + /* + * We need to connect to the button's clicked callback because some + * programs may rely on that the widget in the callback is a GtkButton + */ + if (callback) + g_signal_connect (child->widget, "clicked", + callback, user_data); + + if (type == EGG_TOOLBAR_CHILD_BUTTON || + type == EGG_TOOLBAR_CHILD_RADIOBUTTON || + type == EGG_TOOLBAR_CHILD_TOGGLEBUTTON) + { + if (text) + { + child->label = EGG_TOOL_BUTTON (item)->label; + + if (use_stock) + g_object_set (G_OBJECT (item), "stock_id", text, NULL); + else + egg_tool_button_set_label (EGG_TOOL_BUTTON (item), text); + } + + if (icon) + { + child->icon = icon; + egg_tool_button_set_icon_widget (EGG_TOOL_BUTTON (item), icon); + } + + } + + if ((type != GTK_TOOLBAR_CHILD_SPACE) && tooltip_text) + egg_tool_item_set_tooltip (item, toolbar->tooltips, + tooltip_text, tooltip_private_text); + + toolbar->children = g_list_insert (toolbar->children, child, position); + egg_toolbar_insert_tool_item (toolbar, item, position); + + return child->widget; +} diff --git a/lib/egg/eggtoolbar.h b/lib/egg/eggtoolbar.h new file mode 100644 index 000000000..5420b9dfa --- /dev/null +++ b/lib/egg/eggtoolbar.h @@ -0,0 +1,242 @@ +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * GtkToolbar copyright (C) Federico Mena + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + */ + +#ifndef __EGG_TOOLBAR_H__ +#define __EGG_TOOLBAR_H__ + +#include <gdk/gdk.h> +#include <gtk/gtkcontainer.h> +#include <gtk/gtkenums.h> +#include <gtk/gtktooltips.h> + +#include "eggtoolitem.h" + +/* Not needed, retained for compatibility -Yosh */ +#include <gtk/gtkpixmap.h> +#include <gtk/gtksignal.h> + +G_BEGIN_DECLS + +#define EGG_TYPE_TOOLBAR (egg_toolbar_get_type ()) +#define EGG_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TOOLBAR, EggToolbar)) +#define EGG_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TOOLBAR, EggToolbarClass)) +#define EGG_IS_TOOLBAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TOOLBAR)) +#define EGG_IS_TOOLBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TOOLBAR)) +#define EGG_TOOLBAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TOOLBAR, EggToolbarClass)) + +#ifndef EGG_DISABLE_DEPRECATED +typedef enum +{ + EGG_TOOLBAR_CHILD_SPACE, + EGG_TOOLBAR_CHILD_BUTTON, + EGG_TOOLBAR_CHILD_TOGGLEBUTTON, + EGG_TOOLBAR_CHILD_RADIOBUTTON, + EGG_TOOLBAR_CHILD_WIDGET +} EggToolbarChildType; + +typedef struct _EggToolbarChild EggToolbarChild; + +struct _EggToolbarChild +{ + EggToolbarChildType type; + GtkWidget *widget; + GtkWidget *icon; + GtkWidget *label; +}; + +#endif /* EGG_DISABLE_DEPRECATED */ +typedef struct _EggToolbar EggToolbar; +typedef struct _EggToolbarClass EggToolbarClass; + +struct _EggToolbar +{ + GtkContainer container; + + gint num_children; + GList *children; + GtkOrientation orientation; + GtkToolbarStyle style; + GtkIconSize icon_size; + + GtkTooltips *tooltips; + + gint button_maxw; + gint button_maxh; + + guint style_set_connection; + guint icon_size_connection; + + guint style_set : 1; + guint icon_size_set : 1; +}; + +struct _EggToolbarClass +{ + GtkContainerClass parent_class; + + void (* orientation_changed) (EggToolbar *toolbar, + GtkOrientation orientation); + void (* style_changed) (EggToolbar *toolbar, + GtkToolbarStyle style); + + /* Padding for future expansion */ + void (*_gtk_reserved1) (void); + void (*_gtk_reserved2) (void); + void (*_gtk_reserved3) (void); + void (*_gtk_reserved4) (void); +}; + +GType egg_toolbar_get_type (void) G_GNUC_CONST; +GtkWidget* egg_toolbar_new (void); + +void egg_toolbar_append_tool_item (EggToolbar *toolbar, + EggToolItem *item); +void egg_toolbar_prepend_tool_item (EggToolbar *toolbar, + EggToolItem *item); +void egg_toolbar_insert_tool_item (EggToolbar *toolbar, + EggToolItem *item, + gint pos); +void egg_toolbar_remove_tool_item (EggToolbar *toolbar, + EggToolItem *item); + +/* Style functions */ +void egg_toolbar_set_show_arrow (EggToolbar *toolbar, + gboolean show_arrow); +void egg_toolbar_set_orientation (EggToolbar *toolbar, + GtkOrientation orientation); +void egg_toolbar_set_style (EggToolbar *toolbar, + GtkToolbarStyle style); +void egg_toolbar_set_icon_size (EggToolbar *toolbar, + GtkIconSize icon_size); +void egg_toolbar_set_tooltips (EggToolbar *toolbar, + gboolean enable); +void egg_toolbar_unset_style (EggToolbar *toolbar); +void egg_toolbar_unset_icon_size (EggToolbar *toolbar); +gboolean egg_toolbar_get_show_arrow (EggToolbar *toolbar); +GtkOrientation egg_toolbar_get_orientation (EggToolbar *toolbar); +GtkToolbarStyle egg_toolbar_get_style (EggToolbar *toolbar); +GtkIconSize egg_toolbar_get_icon_size (EggToolbar *toolbar); +gboolean egg_toolbar_get_tooltips (EggToolbar *toolbar); +GList* egg_toolbar_get_tool_items (EggToolbar *toolbar); + + + +#ifndef EGG_DISABLE_DEPRECATED +/* Simple button items */ +GtkWidget* egg_toolbar_append_item (EggToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data); +GtkWidget* egg_toolbar_prepend_item (EggToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data); +GtkWidget* egg_toolbar_insert_item (EggToolbar *toolbar, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position); + +/* Stock Items */ +GtkWidget* egg_toolbar_insert_stock (EggToolbar *toolbar, + const gchar *stock_id, + const char *tooltip_text, + const char *tooltip_private_text, + GtkSignalFunc callback, + gpointer user_data, + gint position); + +/* Space Items */ +void egg_toolbar_append_space (EggToolbar *toolbar); +void egg_toolbar_prepend_space (EggToolbar *toolbar); +void egg_toolbar_insert_space (EggToolbar *toolbar, + gint position); +/* FIXME: Write this function */ +void egg_toolbar_remove_space (EggToolbar *toolbar, + gint position); +/* Any element type */ +GtkWidget* egg_toolbar_append_element (EggToolbar *toolbar, + EggToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data); + +GtkWidget* egg_toolbar_prepend_element (EggToolbar *toolbar, + EggToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data); + +GtkWidget* egg_toolbar_insert_element (EggToolbar *toolbar, + EggToolbarChildType type, + GtkWidget *widget, + const char *text, + const char *tooltip_text, + const char *tooltip_private_text, + GtkWidget *icon, + GtkSignalFunc callback, + gpointer user_data, + gint position); + +/* Generic Widgets */ +void egg_toolbar_append_widget (EggToolbar *toolbar, + GtkWidget *widget, + const char *tooltip_text, + const char *tooltip_private_text); +void egg_toolbar_prepend_widget (EggToolbar *toolbar, + GtkWidget *widget, + const char *tooltip_text, + const char *tooltip_private_text); +void egg_toolbar_insert_widget (EggToolbar *toolbar, + GtkWidget *widget, + const char *tooltip_text, + const char *tooltip_private_text, + gint position); + +#endif /* EGG_DISABLE_DEPRECATED */ + + +G_END_DECLS + +#endif /* __EGG_TOOLBAR_H__ */ diff --git a/lib/egg/eggtoolbutton.c b/lib/egg/eggtoolbutton.c new file mode 100644 index 000000000..7c6e8e865 --- /dev/null +++ b/lib/egg/eggtoolbutton.c @@ -0,0 +1,670 @@ +/* eggtoolbutton.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "eggtoolbutton.h" +#include <gtk/gtkbutton.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkiconfactory.h> +#include <gtk/gtkimage.h> +#include <gtk/gtkimagemenuitem.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkstock.h> +#include <gtk/gtkvbox.h> + +#include <string.h> + +#ifndef _ +# define _(s) (s) +#endif + +enum { + PROP_0, + PROP_LABEL, + PROP_USE_UNDERLINE, + PROP_STOCK_ID, + PROP_ICON_SET, + PROP_ICON_WIDGET, +}; + +static void egg_tool_button_init (EggToolButton *button, + EggToolButtonClass *klass); +static void egg_tool_button_class_init (EggToolButtonClass *klass); + + +static void egg_tool_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void egg_tool_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void egg_tool_button_finalize (GObject *object); + +static void egg_tool_button_show_all (GtkWidget *widget); + +static GtkWidget *egg_tool_button_create_menu_proxy (EggToolItem *item); +static void egg_tool_button_set_orientation (EggToolItem *tool_item, + GtkOrientation orientation); +static void egg_tool_button_set_icon_size (EggToolItem *tool_item, + GtkIconSize icon_size); +static void egg_tool_button_set_toolbar_style (EggToolItem *tool_item, + GtkToolbarStyle style); +static void egg_tool_button_set_relief_style (EggToolItem *tool_item, + GtkReliefStyle style); +static void egg_tool_button_set_tooltip (EggToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private); +static void button_clicked (GtkWidget *widget, + EggToolButton *button); + +static GObjectClass *parent_class = NULL; + +GType +egg_tool_button_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggToolButtonClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_tool_button_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EggToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_tool_button_init, + }; + + type = g_type_register_static (EGG_TYPE_TOOL_ITEM, + "EggToolButton", + &type_info, 0); + } + return type; +} + +static void +egg_tool_button_class_init (EggToolButtonClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + EggToolItemClass *tool_item_class; + + parent_class = g_type_class_peek_parent (klass); + + object_class = (GObjectClass *)klass; + widget_class = (GtkWidgetClass *)klass; + tool_item_class = (EggToolItemClass *)klass; + + object_class->set_property = egg_tool_button_set_property; + object_class->get_property = egg_tool_button_get_property; + object_class->finalize = egg_tool_button_finalize; + + widget_class->show_all = egg_tool_button_show_all; + + tool_item_class->create_menu_proxy = egg_tool_button_create_menu_proxy; + tool_item_class->set_orientation = egg_tool_button_set_orientation; + tool_item_class->set_icon_size = egg_tool_button_set_icon_size; + tool_item_class->set_toolbar_style = egg_tool_button_set_toolbar_style; + tool_item_class->set_relief_style = egg_tool_button_set_relief_style; + tool_item_class->set_tooltip = egg_tool_button_set_tooltip; + + klass->button_type = GTK_TYPE_BUTTON; + + g_object_class_install_property (object_class, + PROP_LABEL, + g_param_spec_string ("label", + _("Label"), + _("Text to show in the item."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_USE_UNDERLINE, + g_param_spec_boolean ("use_underline", + _("Use underline"), + _("Interpret underlines in the item label."), + FALSE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_STOCK_ID, + g_param_spec_string ("stock_id", + _("Stock Id"), + _("The stock icon displayed on the item."), + NULL, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ICON_SET, + g_param_spec_boxed ("icon_set", + _("Icon set"), + _("Icon set to use to draw the item's icon."), + GTK_TYPE_ICON_SET, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ICON_WIDGET, + g_param_spec_object ("icon_widget", + _("Icon widget"), + _("Icon widget to display in the item."), + GTK_TYPE_WIDGET, + G_PARAM_READWRITE)); +} + +static void +egg_tool_button_init (EggToolButton *button, EggToolButtonClass *klass) +{ + EggToolItem *toolitem = EGG_TOOL_ITEM (button); + + toolitem->homogeneous = TRUE; + + /* create button */ + button->button = g_object_new (klass->button_type, NULL); + GTK_WIDGET_UNSET_FLAGS (button->button, GTK_CAN_FOCUS); + g_signal_connect_object (button->button, "clicked", + G_CALLBACK (button_clicked), button, 0); + + button->box = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (button->button), button->box); + gtk_widget_show (button->box); + +#if 0 + button->icon = gtk_image_new(); + gtk_box_pack_start (GTK_BOX (button->box), button->icon, TRUE, TRUE, 0); + gtk_widget_show (button->icon); +#endif + + button->label = gtk_label_new (NULL); + gtk_label_set_use_underline (GTK_LABEL (button->label), TRUE); + gtk_box_pack_start (GTK_BOX (button->box), button->label, FALSE, TRUE, 0); + gtk_widget_show (button->label); + + gtk_container_add (GTK_CONTAINER (button), button->button); + gtk_widget_show (button->button); +} + +static gchar * +elide_underscores (const gchar *original) +{ + gchar *q, *result; + const gchar *p; + gboolean last_underscore; + + q = result = g_malloc (strlen (original) + 1); + last_underscore = FALSE; + + for (p = original; *p; p++) + { + if (!last_underscore && *p == '_') + last_underscore = TRUE; + else + { + last_underscore = FALSE; + *q++ = *p; + } + } + + *q = '\0'; + + return result; +} + +static void +egg_tool_button_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EggToolButton *button = EGG_TOOL_BUTTON (object); + GtkStockItem stock_item; + GtkIconSet *icon_set; + gchar *label_no_mnemonic = NULL; + + switch (prop_id) + { + case PROP_LABEL: + egg_tool_button_set_label (button, g_value_get_string (value)); + break; + case PROP_USE_UNDERLINE: + gtk_label_set_use_underline (GTK_LABEL (button->label), + g_value_get_boolean (value)); + break; + case PROP_STOCK_ID: + g_free (button->stock_id); + button->stock_id = g_value_dup_string (value); + if (!button->label_set) + { + if (gtk_stock_lookup (button->stock_id, &stock_item)) + { + label_no_mnemonic = elide_underscores (stock_item.label); + gtk_label_set_label (GTK_LABEL (button->label), label_no_mnemonic); + g_free (label_no_mnemonic); + } + } + if (!button->icon_set) + { + if (button->icon && !GTK_IS_IMAGE (button->icon)) + { + gtk_container_remove (GTK_CONTAINER (button->box), button->icon); + button->icon = NULL; + } + if (!button->icon) + { + button->icon = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (button->box), button->icon, + TRUE, TRUE, 0); + gtk_box_reorder_child (GTK_BOX (button->box), button->icon, 0); + } + gtk_image_set_from_stock (GTK_IMAGE (button->icon), button->stock_id, + EGG_TOOL_ITEM (button)->icon_size); + } + break; + case PROP_ICON_SET: + if (button->icon && !GTK_IS_IMAGE (button->icon)) + { + gtk_container_remove (GTK_CONTAINER (button->box), button->icon); + button->icon = NULL; + } + if (!button->icon) + { + button->icon = gtk_image_new (); + gtk_box_pack_start (GTK_BOX (button->box), button->icon, + TRUE, TRUE, 0); + gtk_box_reorder_child (GTK_BOX (button->box), button->icon, 0); + } + icon_set = g_value_get_boxed (value); + button->icon_set = (icon_set != NULL); + if (!button->icon_set && button->stock_id) + gtk_image_set_from_stock (GTK_IMAGE (button->icon), button->stock_id, + EGG_TOOL_ITEM (button)->icon_size); + else + gtk_image_set_from_icon_set (GTK_IMAGE (button->icon), icon_set, + EGG_TOOL_ITEM (button)->icon_size); + break; + case PROP_ICON_WIDGET: + egg_tool_button_set_icon_widget (button, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +egg_tool_button_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EggToolButton *button = EGG_TOOL_BUTTON (object); + + switch (prop_id) + { + case PROP_LABEL: + if (button->label_set) + g_value_set_string (value, + gtk_label_get_label (GTK_LABEL (button->label))); + break; + case PROP_USE_UNDERLINE: + g_value_set_boolean (value, + gtk_label_get_use_underline (GTK_LABEL (button->label))); + break; + case PROP_STOCK_ID: + g_value_set_string (value, button->stock_id); + break; + case PROP_ICON_SET: + if (GTK_IS_IMAGE (button->icon) && + GTK_IMAGE (button->icon)->storage_type == GTK_IMAGE_ICON_SET) + { + GtkIconSet *icon_set; + gtk_image_get_icon_set (GTK_IMAGE (button->icon), &icon_set, NULL); + g_value_set_boxed (value, icon_set); + } + else + g_value_set_boxed (value, NULL); + break; + case PROP_ICON_WIDGET: + g_value_set_object (value, button->icon); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +egg_tool_button_finalize (GObject *object) +{ + EggToolButton *button = EGG_TOOL_BUTTON (object); + + g_free (button->stock_id); + button->stock_id = NULL; + + parent_class->finalize (object); +} + +static void +egg_tool_button_show_all (GtkWidget *widget) +{ + EggToolButton *button = EGG_TOOL_BUTTON (widget); + + switch (EGG_TOOL_ITEM (widget)->style) + { + case GTK_TOOLBAR_ICONS: + if (button->icon) gtk_widget_show_all (button->icon); + gtk_widget_hide (button->label); + gtk_widget_show (button->box); + gtk_widget_show (button->button); + break; + case GTK_TOOLBAR_TEXT: + if (button->icon) gtk_widget_hide (button->icon); + gtk_widget_show_all (button->label); + gtk_widget_show (button->box); + gtk_widget_show (button->button); + break; + case GTK_TOOLBAR_BOTH: + case GTK_TOOLBAR_BOTH_HORIZ: + gtk_widget_show_all (button->button); + } + + gtk_widget_show (GTK_WIDGET (button)); +} + +static GtkWidget * +egg_tool_button_create_menu_proxy (EggToolItem *item) +{ + EggToolButton *button = EGG_TOOL_BUTTON (item); + GtkWidget *menu_item; + GtkWidget *image; + const char *label; + + label = gtk_label_get_text (GTK_LABEL (button->label)); + + menu_item = gtk_image_menu_item_new_with_label (label); + + if (GTK_IS_IMAGE (button->icon)) + { + image = gtk_image_new (); + + if (GTK_IMAGE (button->icon)->storage_type == GTK_IMAGE_STOCK) + { + gchar *stock_id; + + gtk_image_get_stock (GTK_IMAGE (button->icon), + &stock_id, NULL); + gtk_image_set_from_stock (GTK_IMAGE (image), stock_id, + GTK_ICON_SIZE_MENU); + } + else if (GTK_IMAGE (button->icon)->storage_type == GTK_IMAGE_ICON_SET) + { + GtkIconSet *icon_set; + + gtk_image_get_icon_set (GTK_IMAGE (button->icon), &icon_set, NULL); + gtk_image_set_from_icon_set (GTK_IMAGE (image), icon_set, + GTK_ICON_SIZE_MENU); + } + else + { + g_warning ("FIXME: Add more cases here"); + } + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_item), image); + } + + g_signal_connect_object (menu_item, "activate", + G_CALLBACK (gtk_button_clicked), + EGG_TOOL_BUTTON (button)->button, + G_CONNECT_SWAPPED); + + return menu_item; +} + +static void +egg_tool_button_set_orientation (EggToolItem *tool_item, + GtkOrientation orientation) +{ + if (tool_item->orientation != orientation) + { + tool_item->orientation = orientation; + } +} + +static void +egg_tool_button_set_icon_size (EggToolItem *tool_item, + GtkIconSize icon_size) +{ + if (tool_item->icon_size != icon_size) + { + EggToolButton *button = EGG_TOOL_BUTTON (tool_item); + char *stock_id; + + if (button->icon && GTK_IS_IMAGE (button->icon) && + gtk_image_get_storage_type (GTK_IMAGE (button->icon)) == GTK_IMAGE_STOCK) + { + gtk_image_get_stock (GTK_IMAGE (button->icon), &stock_id, NULL); + stock_id = g_strdup (stock_id); + gtk_image_set_from_stock (GTK_IMAGE (button->icon), + stock_id, + icon_size); + g_free (stock_id); + } + tool_item->icon_size = icon_size; + } +} + +static void +egg_tool_button_set_toolbar_style (EggToolItem *tool_item, + GtkToolbarStyle style) +{ + EggToolButton *button = EGG_TOOL_BUTTON (tool_item); + + if (tool_item->style != style) + { + tool_item->style = style; + + switch (tool_item->style) + { + case GTK_TOOLBAR_ICONS: + gtk_widget_hide (button->label); + if (button->icon) { + gtk_box_set_child_packing (GTK_BOX (button->box), button->icon, + TRUE, TRUE, 0, GTK_PACK_START); + gtk_widget_show (button->icon); + } + break; + case GTK_TOOLBAR_TEXT: + gtk_box_set_child_packing (GTK_BOX (button->box), button->label, + TRUE, TRUE, 0, GTK_PACK_START); + gtk_widget_show (button->label); + if (button->icon) + gtk_widget_hide (button->icon); + break; + case GTK_TOOLBAR_BOTH: + if (GTK_IS_HBOX (button->box)) + { + GtkWidget *vbox; + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + + if (button->icon) + { + g_object_ref (button->icon); + gtk_container_remove (GTK_CONTAINER (button->box), button->icon); + gtk_box_pack_start (GTK_BOX (vbox), button->icon, + TRUE, TRUE, 0); + g_object_unref (button->icon); + } + + g_object_ref (button->label); + gtk_container_remove (GTK_CONTAINER (button->box), button->label); + gtk_box_pack_start (GTK_BOX (vbox), button->label, FALSE, TRUE, 0); + g_object_unref (button->label); + + gtk_container_remove (GTK_CONTAINER (button->button), button->box); + button->box = vbox; + gtk_container_add (GTK_CONTAINER (button->button), button->box); + } + + gtk_box_set_child_packing (GTK_BOX (button->box), button->label, + FALSE, TRUE, 0, GTK_PACK_START); + gtk_widget_show (button->label); + if (button->icon) { + gtk_box_set_child_packing (GTK_BOX (button->box), button->icon, + TRUE, TRUE, 0, GTK_PACK_START); + gtk_widget_show (button->icon); + } + break; + case GTK_TOOLBAR_BOTH_HORIZ: + if (GTK_IS_VBOX (button->box)) + { + GtkWidget *hbox; + + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + + if (button->icon) + { + g_object_ref (button->icon); + gtk_container_remove (GTK_CONTAINER (button->box), button->icon); + gtk_box_pack_start (GTK_BOX (hbox), button->icon, + TRUE, TRUE, 0); + g_object_unref (button->icon); + } + + g_object_ref (button->label); + gtk_container_remove (GTK_CONTAINER (button->box), button->label); + gtk_box_pack_start (GTK_BOX (hbox), button->label, FALSE, TRUE, 0); + g_object_unref (button->label); + + gtk_container_remove (GTK_CONTAINER (button->button), button->box); + button->box = hbox; + gtk_container_add (GTK_CONTAINER (button->button), button->box); + } + + gtk_box_set_child_packing (GTK_BOX (button->box), button->label, + TRUE, TRUE, 0, GTK_PACK_START); + gtk_widget_show (button->label); + if (button->icon) { + gtk_box_set_child_packing (GTK_BOX (button->box), button->icon, + FALSE, TRUE, 0, GTK_PACK_START); + gtk_widget_show (button->icon); + } + break; + } + } +} + +static void +egg_tool_button_set_relief_style (EggToolItem *tool_item, + GtkReliefStyle style) +{ + gtk_button_set_relief (GTK_BUTTON (EGG_TOOL_BUTTON (tool_item)->button), style); +} + +static void +egg_tool_button_set_tooltip (EggToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private) +{ + gtk_tooltips_set_tip (tooltips, EGG_TOOL_BUTTON (tool_item)->button, + tip_text, tip_private); +} + +static void +button_clicked (GtkWidget *widget, EggToolButton *button) +{ + g_signal_emit_by_name (button, "clicked"); +} + +EggToolItem * +egg_tool_button_new_from_stock (const gchar *stock_id) +{ + EggToolButton *button; + + button = g_object_new (EGG_TYPE_TOOL_BUTTON, + "stock_id", stock_id, + "use_underline", TRUE, + NULL); + + return EGG_TOOL_ITEM (button); +} + +EggToolItem * +egg_tool_button_new (void) +{ + EggToolButton *button; + + button = g_object_new (EGG_TYPE_TOOL_BUTTON, + NULL); + + return EGG_TOOL_ITEM (button); +} + +void +egg_tool_button_set_icon_widget (EggToolButton *button, + GtkWidget *icon) +{ + g_return_if_fail (EGG_IS_TOOL_BUTTON (button)); + g_return_if_fail (GTK_IS_WIDGET (icon)); + + if (button->icon) + gtk_container_remove (GTK_CONTAINER (button->box), button->icon); + button->icon = NULL; + + button->icon_set = (icon != NULL); + if (icon) + { + button->icon = icon; + gtk_box_pack_start (GTK_BOX (button->box), button->icon, + TRUE, TRUE, 0); + gtk_box_reorder_child (GTK_BOX (button->box), button->icon, 0); + } + else if (button->stock_id) + { + button->icon = gtk_image_new_from_stock (button->stock_id, + EGG_TOOL_ITEM (button)->icon_size); + gtk_box_pack_start (GTK_BOX (button->box), button->icon, + TRUE, TRUE, 0); + } +} + +void +egg_tool_button_set_label (EggToolButton *button, + const gchar *label) +{ + gchar *label_no_mnemonic = NULL; + GtkStockItem stock_item; + + g_return_if_fail (EGG_IS_TOOL_BUTTON (button)); + g_return_if_fail (label != NULL); + + button->label_set = (label != NULL); + + if (label) + label_no_mnemonic = elide_underscores (label); + else if (button->stock_id && gtk_stock_lookup (button->stock_id, &stock_item)) + label_no_mnemonic = elide_underscores (stock_item.label); + + gtk_label_set_label (GTK_LABEL (button->label), label_no_mnemonic); + g_free (label_no_mnemonic); +} + diff --git a/lib/egg/eggtoolbutton.h b/lib/egg/eggtoolbutton.h new file mode 100644 index 000000000..cb0c0b15e --- /dev/null +++ b/lib/egg/eggtoolbutton.h @@ -0,0 +1,74 @@ +/* eggtoolbutton.h + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TOOL_BUTTON_H__ +#define __EGG_TOOL_BUTTON_H__ + +#include "eggtoolitem.h" + +G_BEGIN_DECLS + +#define EGG_TYPE_TOOL_BUTTON (egg_tool_button_get_type ()) +#define EGG_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TOOL_BUTTON, EggToolButton)) +#define EGG_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TOOL_BUTTON, EggToolButtonClass)) +#define EGG_IS_TOOL_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TOOL_BUTTON)) +#define EGG_IS_TOOL_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_TOOL_BUTTON)) +#define EGG_TOOL_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_TOOL_BUTTON, EggToolButtonClass)) + +typedef struct _EggToolButton EggToolButton; +typedef struct _EggToolButtonClass EggToolButtonClass; + +struct _EggToolButton +{ + EggToolItem parent; + + /*< private >*/ + GtkWidget *button; + GtkWidget *box; + GtkWidget *label; + GtkWidget *icon; + + gchar *stock_id; + guint label_set : 1; + guint icon_set : 1; +}; + +struct _EggToolButtonClass +{ + EggToolItemClass parent_class; + + GType button_type; +}; + +GType egg_tool_button_get_type (void); +EggToolItem *egg_tool_button_new (void); +EggToolItem *egg_tool_button_new_from_stock (const gchar *stock_id); + + +void egg_tool_button_set_icon_widget (EggToolButton *button, + GtkWidget *icon); +void egg_tool_button_set_label (EggToolButton *button, + const gchar *label); + + +G_END_DECLS + +#endif /* __EGG_TOOL_BUTTON_H__ */ diff --git a/lib/egg/eggtoolitem.c b/lib/egg/eggtoolitem.c new file mode 100644 index 000000000..0bb234286 --- /dev/null +++ b/lib/egg/eggtoolitem.c @@ -0,0 +1,416 @@ +/* eggtoolitem.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "eggtoolitem.h" +#include "eggmarshalers.h" + +#ifndef _ +# define _(s) (s) +#endif + +enum { + CLICKED, + CREATE_MENU_PROXY, + SET_ORIENTATION, + SET_ICON_SIZE, + SET_TOOLBAR_STYLE, + SET_RELIEF_STYLE, + SET_TOOLTIP, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_VISIBLE_HORIZONTAL, + PROP_VISIBLE_VERTICAL, + PROP_HOMOGENEOUS, + PROP_ORIENTATION +}; + +static void egg_tool_item_init (EggToolItem *toolitem); +static void egg_tool_item_class_init (EggToolItemClass *class); + +static void egg_tool_item_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void egg_tool_item_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); + +static void egg_tool_item_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void egg_tool_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static GtkWidget *egg_tool_item_create_menu_proxy (EggToolItem *item); + + +static GObjectClass *parent_class = NULL; +static guint toolitem_signals[LAST_SIGNAL] = { 0 }; + +GType +egg_tool_item_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EggToolItemClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) egg_tool_item_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (EggToolItem), + 0, /* n_preallocs */ + (GInstanceInitFunc) egg_tool_item_init, + }; + + type = g_type_register_static (GTK_TYPE_BIN, + "EggToolItem", + &type_info, 0); + } + return type; +} + +static gboolean +create_proxy_accumulator (GSignalInvocationHint *hint, + GValue *return_accumulator, + const GValue *handler_return, + gpointer user_data) +{ + GObject *proxy; + gboolean continue_emission; + + proxy = g_value_get_object(handler_return); + g_value_set_object(return_accumulator, proxy); + continue_emission = (proxy == NULL); + + return continue_emission; +} + +static void +egg_tool_item_class_init (EggToolItemClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (klass); + object_class = (GObjectClass *)klass; + widget_class = (GtkWidgetClass *)klass; + + object_class->set_property = egg_tool_item_set_property; + object_class->get_property = egg_tool_item_get_property; + + widget_class->size_request = egg_tool_item_size_request; + widget_class->size_allocate = egg_tool_item_size_allocate; + + klass->create_menu_proxy = egg_tool_item_create_menu_proxy; + + g_object_class_install_property (object_class, + PROP_VISIBLE_HORIZONTAL, + g_param_spec_boolean ("visible_horizontal", + _("Visible when horizontal"), + _("Whether the toolbar item is visible when the toolbar is in a horizontal orientation."), + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_VISIBLE_VERTICAL, + g_param_spec_boolean ("visible_vertical", + _("Visible when vertical"), + _("Whether the toolbar item is visible when the toolbar is in a vertical orientation."), + TRUE, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_HOMOGENEOUS, + g_param_spec_boolean ("homogeneous", + _("Homogeneous size"), + _("Whether the toolbar item should be the same size as other homogeneous items."), + FALSE, + G_PARAM_READWRITE)); + + toolitem_signals[CLICKED] = + g_signal_new ("clicked", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EggToolItemClass, clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + toolitem_signals[CREATE_MENU_PROXY] = + g_signal_new ("create_menu_proxy", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggToolItemClass, create_menu_proxy), + create_proxy_accumulator, NULL, + _egg_marshal_OBJECT__VOID, + GTK_TYPE_WIDGET, 0); + toolitem_signals[SET_ORIENTATION] = + g_signal_new ("set_orientation", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggToolItemClass, set_orientation), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_ORIENTATION); + toolitem_signals[SET_ICON_SIZE] = + g_signal_new ("set_icon_size", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggToolItemClass, set_icon_size), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_ICON_SIZE); + toolitem_signals[SET_TOOLBAR_STYLE] = + g_signal_new ("set_toolbar_style", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggToolItemClass, set_toolbar_style), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_TOOLBAR_STYLE); + toolitem_signals[SET_RELIEF_STYLE] = + g_signal_new ("set_relief_style", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggToolItemClass, set_relief_style), + NULL, NULL, + g_cclosure_marshal_VOID__ENUM, + G_TYPE_NONE, 1, + GTK_TYPE_RELIEF_STYLE); + toolitem_signals[SET_TOOLTIP] = + g_signal_new ("set_tooltip", + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EggToolItemClass, set_tooltip), + NULL, NULL, + _egg_marshal_VOID__OBJECT_STRING_STRING, + G_TYPE_NONE, 3, + GTK_TYPE_TOOLTIPS, + G_TYPE_STRING, + G_TYPE_STRING); + +} + +static void +egg_tool_item_init (EggToolItem *toolitem) +{ + toolitem->visible_horizontal = TRUE; + toolitem->visible_vertical = TRUE; + toolitem->homogeneous = FALSE; + + toolitem->orientation = GTK_ORIENTATION_HORIZONTAL; + toolitem->icon_size = GTK_ICON_SIZE_LARGE_TOOLBAR; + toolitem->style = GTK_TOOLBAR_BOTH; +} + +static void +egg_tool_item_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EggToolItem *toolitem = EGG_TOOL_ITEM (object); + + switch (prop_id) + { + case PROP_VISIBLE_HORIZONTAL: + toolitem->visible_horizontal = g_value_get_boolean (value); + break; + case PROP_VISIBLE_VERTICAL: + toolitem->visible_vertical = g_value_get_boolean (value); + break; + case PROP_HOMOGENEOUS: + toolitem->homogeneous = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +egg_tool_item_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EggToolItem *toolitem = EGG_TOOL_ITEM (object); + + switch (prop_id) + { + case PROP_VISIBLE_HORIZONTAL: + g_value_set_boolean (value, toolitem->visible_horizontal); + break; + case PROP_VISIBLE_VERTICAL: + g_value_set_boolean (value, toolitem->visible_vertical); + break; + case PROP_HOMOGENEOUS: + g_value_set_boolean (value, toolitem->homogeneous); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +egg_tool_item_size_request (GtkWidget *widget, + GtkRequisition *requisition) +{ + GtkBin *bin = GTK_BIN (widget); + + if (bin->child) + gtk_widget_size_request (bin->child, requisition); + + requisition->width += GTK_CONTAINER (widget)->border_width * 2; + requisition->height += GTK_CONTAINER (widget)->border_width * 2; +} + +static void +egg_tool_item_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkBin *bin = GTK_BIN (widget); + GtkAllocation child_allocation; + + widget->allocation = *allocation; + + if (bin->child && GTK_WIDGET_VISIBLE (bin->child)) + { + child_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width; + child_allocation.y = allocation->y + GTK_CONTAINER (widget)->border_width; + child_allocation.width = allocation->width - GTK_CONTAINER (widget)->border_width * 2; + child_allocation.height = allocation->height - GTK_CONTAINER (widget)->border_width * 2; + + gtk_widget_size_allocate (bin->child, &child_allocation); + } +} + +static GtkWidget * +egg_tool_item_create_menu_proxy (EggToolItem *item) +{ + if (GTK_BIN (item)->child) + return NULL; + else + return gtk_separator_menu_item_new (); +} + +EggToolItem * +egg_tool_item_new (void) +{ + EggToolItem *item; + + item = g_object_new (EGG_TYPE_TOOL_ITEM, NULL); + + return item; +} + +void +egg_tool_item_set_orientation (EggToolItem *tool_item, + GtkOrientation orientation) +{ + g_return_if_fail (EGG_IS_TOOL_ITEM (tool_item)); + + g_signal_emit (tool_item, toolitem_signals[SET_ORIENTATION], 0, orientation); +} + +void +egg_tool_item_set_icon_size (EggToolItem *tool_item, + GtkIconSize icon_size) +{ + g_return_if_fail (EGG_IS_TOOL_ITEM (tool_item)); + + g_signal_emit (tool_item, toolitem_signals[SET_ICON_SIZE], 0, icon_size); +} + +void +egg_tool_item_set_toolbar_style (EggToolItem *tool_item, + GtkToolbarStyle style) +{ + g_return_if_fail (EGG_IS_TOOL_ITEM (tool_item)); + + g_signal_emit (tool_item, toolitem_signals[SET_TOOLBAR_STYLE], 0, style); +} + +void +egg_tool_item_set_relief_style (EggToolItem *tool_item, + GtkReliefStyle style) +{ + g_return_if_fail (EGG_IS_TOOL_ITEM (tool_item)); + + g_signal_emit (tool_item, toolitem_signals[SET_RELIEF_STYLE], 0, style); +} + +void +egg_tool_item_set_expandable (EggToolItem *tool_item, + gboolean expandable) +{ + if ((expandable && tool_item->expandable) || + (!expandable && !tool_item->expandable)) + return; + + tool_item->expandable = expandable; + gtk_widget_queue_resize (GTK_WIDGET (tool_item)); +} + +void +egg_tool_item_set_pack_end (EggToolItem *tool_item, + gboolean pack_end) +{ + if ((pack_end && tool_item->pack_end) || + (!pack_end && !tool_item->pack_end)) + return; + + tool_item->pack_end = pack_end; + gtk_widget_queue_resize (GTK_WIDGET (tool_item)); +} + +void +egg_tool_item_set_homogeneous (EggToolItem *tool_item, + gboolean homogeneous) +{ + if ((homogeneous && tool_item->homogeneous) || + (!homogeneous && !tool_item->homogeneous)) + return; + + tool_item->homogeneous = homogeneous; + gtk_widget_queue_resize (GTK_WIDGET (tool_item)); +} + +void +egg_tool_item_set_tooltip (EggToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private) +{ + g_return_if_fail (EGG_IS_TOOL_ITEM (tool_item)); + + g_signal_emit (tool_item, toolitem_signals[SET_TOOLTIP], 0, + tooltips, tip_text, tip_private); +} diff --git a/lib/egg/eggtoolitem.h b/lib/egg/eggtoolitem.h new file mode 100644 index 000000000..222e095f9 --- /dev/null +++ b/lib/egg/eggtoolitem.h @@ -0,0 +1,98 @@ +/* eggtoolitem.c + * + * Copyright (C) 2002 Anders Carlsson <andersca@codefactory.se> + * Copyright (C) 2002 James Henstridge <james@daa.com.au> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __EGG_TOOL_ITEM_H__ +#define __EGG_TOOL_ITEM_H__ + +#include <gtk/gtkbin.h> +#include <gtk/gtktooltips.h> + +#define EGG_TYPE_TOOL_ITEM (egg_tool_item_get_type ()) +#define EGG_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TOOL_ITEM, EggToolItem)) +#define EGG_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TOOL_ITEM, EggToolItemClass)) +#define EGG_IS_TOOL_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TOOL_ITEM)) +#define EGG_IS_TOOL_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EGG_TYPE_TOOL_ITEM)) +#define EGG_TOOL_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EGG_TYPE_TOOL_ITEM, EggToolItemClass)) + +typedef struct _EggToolItem EggToolItem; +typedef struct _EggToolItemClass EggToolItemClass; + +struct _EggToolItem +{ + GtkBin parent; + + GtkOrientation orientation; + GtkIconSize icon_size; + GtkToolbarStyle style; + + gchar *tip_text; + gchar *tip_private; + + guint visible_horizontal : 1; + guint visible_vertical : 1; + guint homogeneous : 1; + guint expandable : 1; + guint pack_end : 1; +}; + +struct _EggToolItemClass +{ + GtkBinClass parent_class; + + void (* clicked) (EggToolItem *tool_item); + GtkWidget *(* create_menu_proxy) (EggToolItem *tool_item); + void (* set_orientation) (EggToolItem *tool_item, + GtkOrientation orientation); + void (* set_icon_size) (EggToolItem *tool_item, + GtkIconSize icon_size); + void (* set_toolbar_style) (EggToolItem *tool_item, + GtkToolbarStyle style); + void (* set_relief_style) (EggToolItem *tool_item, + GtkReliefStyle relief_style); + void (* set_tooltip) (EggToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private); +}; + +GType egg_tool_item_get_type (void); +EggToolItem *egg_tool_item_new (void); + +void egg_tool_item_set_orientation (EggToolItem *tool_item, + GtkOrientation orientation); +void egg_tool_item_set_icon_size (EggToolItem *tool_item, + GtkIconSize icon_size); +void egg_tool_item_set_toolbar_style (EggToolItem *tool_item, + GtkToolbarStyle style); +void egg_tool_item_set_relief_style (EggToolItem *tool_item, + GtkReliefStyle style); +void egg_tool_item_set_homogeneous (EggToolItem *tool_item, + gboolean homogeneous); +void egg_tool_item_set_expandable (EggToolItem *tool_item, + gboolean expandable); +void egg_tool_item_set_pack_end (EggToolItem *tool_item, + gboolean pack_end); +void egg_tool_item_set_tooltip (EggToolItem *tool_item, + GtkTooltips *tooltips, + const gchar *tip_text, + const gchar *tip_private); + +#endif /* __EGG_TOOL_ITEM_H__ */ diff --git a/lib/egg/prop-editor.h b/lib/egg/prop-editor.h new file mode 100644 index 000000000..1f86d9be1 --- /dev/null +++ b/lib/egg/prop-editor.h @@ -0,0 +1,31 @@ +/* prop-editor.h + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include <gtk/gtkwidget.h> + +#ifndef __PROP_EDITOR_H__ +#define __PROP_EDITOR_H__ + +G_BEGIN_DECLS + +GtkWidget *create_prop_editor (GObject *object, + GType type); + +G_END_DECLS + +#endif /* __PROP_EDITOR_H__ */ diff --git a/lib/ephy-gui.c b/lib/ephy-gui.c index fe4018d38..90d282b3d 100644 --- a/lib/ephy-gui.c +++ b/lib/ephy-gui.c @@ -39,13 +39,12 @@ ephy_gui_menu_position_under_widget (GtkMenu *menu, gpointer user_data) { GtkWidget *w = GTK_WIDGET (user_data); - gint width, height; gint screen_width, screen_height; GtkRequisition requisition; - gdk_drawable_get_size (w->window, &width, &height); gdk_window_get_origin (w->window, x, y); - *y = *y + height; + *x += w->allocation.x; + *y += w->allocation.y + w->allocation.height; gtk_widget_size_request (GTK_WIDGET (menu), &requisition); @@ -54,6 +53,7 @@ ephy_gui_menu_position_under_widget (GtkMenu *menu, *x = CLAMP (*x, 0, MAX (0, screen_width - requisition.width)); *y = CLAMP (*y, 0, MAX (0, screen_height - requisition.height)); + g_print ("result %d\n", *y); } /** diff --git a/lib/toolbar/Makefile.am b/lib/toolbar/Makefile.am deleted file mode 100644 index d616b1ef5..000000000 --- a/lib/toolbar/Makefile.am +++ /dev/null @@ -1,44 +0,0 @@ -INCLUDES = \ - -I$(top_srcdir)/lib \ - -I$(top_srcdir)/lib/widgets \ - $(WARN_CFLAGS) \ - $(EPIPHANY_DEPENDENCY_CFLAGS) \ - -DSHARE_DIR=\"$(pkgdatadir)\" \ - -DG_DISABLE_DEPRECATED \ - -DGDK_DISABLE_DEPRECATED \ - -DGTK_DISABLE_DEPRECATED \ - -DGDK_PIXBUF_DISABLE_DEPRECATED \ - -DGNOME_DISABLE_DEPRECATED - -noinst_LTLIBRARIES = libephytoolbar.la - -libephytoolbar_la_SOURCES = \ - ephy-toolbar.h \ - ephy-toolbar.c \ - ephy-toolbar-bonobo-view.c \ - ephy-toolbar-bonobo-view.h \ - ephy-toolbar-editor.h \ - ephy-toolbar-editor.c \ - ephy-toolbar-item.h \ - ephy-toolbar-item.c \ - ephy-toolbar-item-factory.h \ - ephy-toolbar-item-factory.c \ - ephy-toolbar-tree-model.h \ - ephy-toolbar-tree-model.c \ - ephy-tb-button.c \ - ephy-tb-button.h \ - ephy-tbi-favicon.h \ - ephy-tbi-favicon.c \ - ephy-tbi-location.h \ - ephy-tbi-location.c \ - ephy-tbi-navigation-history.h \ - ephy-tbi-navigation-history.c \ - ephy-tbi-separator.h \ - ephy-tbi-separator.c \ - ephy-tbi-spinner.h \ - ephy-tbi-spinner.c \ - ephy-tbi-std-toolitem.h \ - ephy-tbi-std-toolitem.c \ - ephy-tbi-zoom.h \ - ephy-tbi-zoom.c - diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am index 9ffe03f72..23aad4b01 100644 --- a/lib/widgets/Makefile.am +++ b/lib/widgets/Makefile.am @@ -1,5 +1,6 @@ INCLUDES = \ -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/egg \ $(WARN_CFLAGS) \ $(EPIPHANY_DEPENDENCY_CFLAGS) \ -DSHARE_DIR=\"$(pkgdatadir)\" \ @@ -16,6 +17,8 @@ libephywidgets_la_SOURCES = \ eggtreemodelfilter.h \ eggtreemultidnd.c \ eggtreemultidnd.h \ + ephy-arrow-toolbutton.c \ + ephy-arrow-toolbutton.h \ ephy-autocompletion-window.c \ ephy-autocompletion-window.h \ ephy-ellipsizing-label.c \ diff --git a/lib/widgets/ephy-arrow-toolbutton.c b/lib/widgets/ephy-arrow-toolbutton.c new file mode 100644 index 000000000..abc5ed4f2 --- /dev/null +++ b/lib/widgets/ephy-arrow-toolbutton.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2002 Christophe Fergeau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-arrow-toolbutton.h" +#include "ephy-marshal.h" +#include "ephy-gui.h" +#include "ephy-debug.h" + +#include <gtk/gtkarrow.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtkmenu.h> +#include <gtk/gtkmain.h> + +struct EphyArrowToolButtonPrivate +{ + GtkWidget *arrow_widget; + GtkWidget *button; + GtkMenu *menu; +}; + +enum EphyArrowToolButtonSignalsEnum { + EPHY_ARROW_TOOL_BUTTON_MENU_ACTIVATED, + EPHY_ARROW_TOOL_BUTTON_LAST_SIGNAL +}; + +/* GObject boilerplate code */ +static void ephy_arrow_toolbutton_init (EphyArrowToolButton *arrow_toolbutton); +static void ephy_arrow_toolbutton_class_init (EphyArrowToolButtonClass *klass); +static void ephy_arrow_toolbutton_finalize (GObject *object); + +static GObjectClass *parent_class = NULL; + +static gint EphyArrowToolButtonSignals[EPHY_ARROW_TOOL_BUTTON_LAST_SIGNAL]; + +GType +ephy_arrow_toolbutton_get_type (void) +{ + static GType ephy_arrow_toolbutton_type = 0; + + if (ephy_arrow_toolbutton_type == 0) + { + static const GTypeInfo our_info = + { + sizeof (EphyArrowToolButtonClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) ephy_arrow_toolbutton_class_init, + NULL, + NULL, /* class_data */ + sizeof (EphyArrowToolButton), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_arrow_toolbutton_init + }; + + ephy_arrow_toolbutton_type = g_type_register_static (EGG_TYPE_TOOL_BUTTON, + "EphyArrowToolButton", + &our_info, 0); + } + + return ephy_arrow_toolbutton_type; +} + +static void +ephy_arrow_toolbutton_class_init (EphyArrowToolButtonClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + parent_class = g_type_class_peek_parent (klass); + + object_class->finalize = ephy_arrow_toolbutton_finalize; + + EphyArrowToolButtonSignals[EPHY_ARROW_TOOL_BUTTON_MENU_ACTIVATED] = + g_signal_new + ("menu-activated", G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (EphyArrowToolButtonClass, menu_activated), + NULL, NULL, + ephy_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +button_state_changed_cb (GtkWidget *widget, + GtkStateType previous_state, + EphyArrowToolButton *b) +{ + EphyArrowToolButtonPrivate *p = b->priv; + GtkWidget *button; + GtkStateType state = GTK_WIDGET_STATE (widget); + GtkStateType other; + + if (state == GTK_STATE_ACTIVE || + state == GTK_STATE_SELECTED || + state == GTK_STATE_INSENSITIVE) + { + return; + } + + button = (widget == p->arrow_widget) ? p->button : p->arrow_widget; + other = GTK_WIDGET_STATE (button); + + if (state != other) + { + gtk_widget_set_state (button, state); + } +} + +static void +popup_menu_under_arrow (EphyArrowToolButton *b, GdkEventButton *event) +{ + EphyArrowToolButtonPrivate *p = b->priv; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->arrow_widget), TRUE); + LOG ("Emit menu activated signal"); + g_signal_emit (b, EphyArrowToolButtonSignals[EPHY_ARROW_TOOL_BUTTON_MENU_ACTIVATED], 0); + gtk_menu_popup (p->menu, NULL, NULL, ephy_gui_menu_position_under_widget, b, + event ? event->button : 0, + event ? event->time : gtk_get_current_event_time ()); +} + +static void +menu_deactivated_cb (GtkMenuShell *ms, EphyArrowToolButton *b) +{ + EphyArrowToolButtonPrivate *p = b->priv; + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (p->arrow_widget), FALSE); +} + +static gboolean +arrow_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, EphyArrowToolButton *b) +{ + popup_menu_under_arrow (b, event); + return TRUE; +} + +static gboolean +arrow_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, EphyArrowToolButton *b) +{ + if (event->keyval == GDK_space + || event->keyval == GDK_KP_Space + || event->keyval == GDK_Return + || event->keyval == GDK_KP_Enter + || event->keyval == GDK_Menu) + { + popup_menu_under_arrow (b, NULL); + } + + return FALSE; +} + +static void +ephy_arrow_toolbutton_init (EphyArrowToolButton *arrowtb) +{ + GtkWidget *hbox; + GtkWidget *arrow; + GtkWidget *arrow_button; + GtkWidget *real_button; + + arrowtb->priv = g_new (EphyArrowToolButtonPrivate, 1); + + egg_tool_item_set_homogeneous (EGG_TOOL_ITEM (arrowtb), FALSE); + + hbox = gtk_hbox_new (FALSE, 0); + gtk_widget_show (hbox); + real_button = EGG_TOOL_BUTTON (arrowtb)->button; + g_object_ref (real_button); + gtk_container_remove (GTK_CONTAINER (arrowtb), real_button); + gtk_container_add (GTK_CONTAINER (hbox), real_button); + gtk_container_add (GTK_CONTAINER (arrowtb), hbox); + + arrow_button = gtk_toggle_button_new (); + gtk_widget_show (arrow_button); + arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_widget_show (arrow); + gtk_button_set_relief (GTK_BUTTON (arrow_button), GTK_RELIEF_NONE); + gtk_container_add (GTK_CONTAINER (arrow_button), arrow); + + gtk_box_pack_end (GTK_BOX (hbox), arrow_button, + FALSE, FALSE, 0); + + arrowtb->priv->button = real_button; + arrowtb->priv->arrow_widget = arrow_button; + + arrowtb->priv->menu = GTK_MENU (gtk_menu_new ()); + g_signal_connect (arrowtb->priv->menu, "deactivate", + G_CALLBACK (menu_deactivated_cb), arrowtb); + + g_signal_connect (real_button, "state_changed", + G_CALLBACK (button_state_changed_cb), + arrowtb); + g_signal_connect (arrow_button, "state_changed", + G_CALLBACK (button_state_changed_cb), + arrowtb); + g_signal_connect (arrow_button, "key_press_event", + G_CALLBACK (arrow_key_press_event_cb), + arrowtb); + g_signal_connect (arrow_button, "button_press_event", + G_CALLBACK (arrow_button_press_event_cb), + arrowtb); +} + +static void +ephy_arrow_toolbutton_finalize (GObject *object) +{ + EphyArrowToolButton *arrow_toolbutton = EPHY_ARROW_TOOLBUTTON (object); + + gtk_widget_destroy (GTK_WIDGET (arrow_toolbutton->priv->menu)); + + g_free (arrow_toolbutton->priv); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +GtkMenuShell * +ephy_arrow_toolbutton_get_menu (EphyArrowToolButton *b) +{ + return GTK_MENU_SHELL (b->priv->menu); +} diff --git a/lib/widgets/ephy-arrow-toolbutton.h b/lib/widgets/ephy-arrow-toolbutton.h new file mode 100644 index 000000000..7352d6c1a --- /dev/null +++ b/lib/widgets/ephy-arrow-toolbutton.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2002 Christophe Fergeau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_ARROW_TOOLBUTTON_H +#define EPHY_ARROW_TOOLBUTTON_H + +#include <glib.h> +#include <gtk/gtkmenushell.h> + +#include "eggtoolbutton.h" + +G_BEGIN_DECLS + +typedef struct EphyArrowToolButtonClass EphyArrowToolButtonClass; + +#define EPHY_ARROW_TOOLBUTTON_TYPE (ephy_arrow_toolbutton_get_type ()) +#define EPHY_ARROW_TOOLBUTTON(obj) (GTK_CHECK_CAST ((obj), EPHY_ARROW_TOOLBUTTON_TYPE, EphyArrowToolButton)) +#define EPHY_ARROW_TOOLBUTTON_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), EPHY_ARROW_TOOLBUTTON_TYPE, EphyArrowToolButtonClass)) +#define IS_EPHY_ARROW_TOOLBUTTON(obj) (GTK_CHECK_TYPE ((obj), EPHY_ARROW_TOOLBUTTON_TYPE)) +#define IS_EPHY_ARROW_TOOLBUTTON_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), EPHY_ARROW_TOOLBUTTON)) + +typedef struct EphyArrowToolButton EphyArrowToolButton; +typedef struct EphyArrowToolButtonPrivate EphyArrowToolButtonPrivate; + +struct EphyArrowToolButton +{ + EggToolButton parent; + EphyArrowToolButtonPrivate *priv; +}; + +struct EphyArrowToolButtonClass +{ + EggToolButtonClass parent_class; + + void (*menu_activated) (EphyArrowToolButton *b); +}; + +GType ephy_arrow_toolbutton_get_type (void); + +GtkMenuShell *ephy_arrow_toolbutton_get_menu (EphyArrowToolButton *b); + +G_END_DECLS; + +#endif /* EPHY_ARROW_TOOLBUTTON_H */ diff --git a/lib/widgets/ephy-location-entry.c b/lib/widgets/ephy-location-entry.c index d2702c6b4..5a947a7b2 100644 --- a/lib/widgets/ephy-location-entry.c +++ b/lib/widgets/ephy-location-entry.c @@ -158,10 +158,10 @@ ephy_location_entry_finalize_impl (GObject *o) G_OBJECT_CLASS (gtk_hbox_class)->finalize (o); } -EphyLocationEntry * +GtkWidget * ephy_location_entry_new (void) { - return EPHY_LOCATION_ENTRY (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL)); + return GTK_WIDGET (g_object_new (EPHY_TYPE_LOCATION_ENTRY, NULL)); } static void diff --git a/lib/widgets/ephy-location-entry.h b/lib/widgets/ephy-location-entry.h index eebacc770..d292ffb0c 100644 --- a/lib/widgets/ephy-location-entry.h +++ b/lib/widgets/ephy-location-entry.h @@ -63,10 +63,10 @@ struct _EphyLocationEntry }; GType ephy_location_entry_get_type (void); -EphyLocationEntry * ephy_location_entry_new (void); +GtkWidget *ephy_location_entry_new (void); void ephy_location_entry_set_location (EphyLocationEntry *w, const gchar *new_location); -gchar * ephy_location_entry_get_location (EphyLocationEntry *w); +gchar *ephy_location_entry_get_location (EphyLocationEntry *w); void ephy_location_entry_set_autocompletion (EphyLocationEntry *w, EphyAutocompletion *ac); void ephy_location_entry_activate (EphyLocationEntry *w); diff --git a/lib/widgets/ephy-spinner.c b/lib/widgets/ephy-spinner.c index e4462f889..d1caf8fba 100644 --- a/lib/widgets/ephy-spinner.c +++ b/lib/widgets/ephy-spinner.c @@ -396,8 +396,8 @@ ephy_spinner_expose (GtkWidget *widget, GdkEventExpose *event) height = gdk_pixbuf_get_height (pixbuf); /* Compute the offsets for the image centered on our allocation */ - x_offset = widget->allocation.x + (widget->allocation.width - width) / 2; - y_offset = widget->allocation.y + (widget->allocation.height - height) / 2; + x_offset = (widget->allocation.width - width) / 2; + y_offset = (widget->allocation.height - height) / 2; pix_area.x = x_offset; pix_area.y = y_offset; diff --git a/src/Makefile.am b/src/Makefile.am index e2b4a65e2..875926c3b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,6 +3,7 @@ SUBDIRS = bookmarks INCLUDES = \ -I$(top_srcdir)/embed \ -I$(top_srcdir)/lib \ + -I$(top_srcdir)/lib/egg \ -I$(top_srcdir)/lib/widgets \ -I$(top_srcdir)/lib/toolbar \ -I$(top_srcdir)/src/bookmarks \ @@ -45,19 +46,22 @@ epiphany_SOURCES = \ appearance-prefs.h \ ephy-automation.c \ ephy-automation.h \ + ephy-favicon-action.c \ + ephy-favicon-action.h \ ephy-favorites-menu.c \ ephy-favorites-menu.h \ ephy-history-model.c \ ephy-history-model.h \ + ephy-location-action.c \ + ephy-location-action.h \ ephy-main.c \ - ephy-navigation-button.c \ - ephy-navigation-button.h \ + ephy-navigation-action.c \ ephy-shell.c \ ephy-shell.h \ + ephy-spinner-action.c \ + ephy-spinner-action.h \ ephy-tab.c \ ephy-tab.h \ - ephy-tbi.c \ - ephy-tbi.h \ ephy-window.c \ ephy-window.h \ general-prefs.c \ diff --git a/src/ephy-favicon-action.c b/src/ephy-favicon-action.c new file mode 100644 index 000000000..9fa68acf2 --- /dev/null +++ b/src/ephy-favicon-action.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-favicon-action.h" +#include "eggtoolitem.h" +#include "ephy-window.h" +#include "ephy-tab.h" +#include "ephy-dnd.h" +#include "ephy-favicon-cache.h" +#include "ephy-shell.h" + +struct EphyFaviconActionPrivate +{ + EphyWindow *window; + char *icon; +}; + +enum +{ + PROP_0, + PROP_WINDOW, + PROP_ICON +}; + +static void ephy_favicon_action_init (EphyFaviconAction *action); +static void ephy_favicon_action_class_init (EphyFaviconActionClass *class); + +static GObjectClass *parent_class = NULL; + +GType +ephy_favicon_action_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EphyFaviconActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ephy_favicon_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EphyFaviconAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_favicon_action_init, + }; + + type = g_type_register_static (EGG_TYPE_ACTION, + "EphyFaviconAction", + &type_info, 0); + } + return type; +} + +static GtkWidget * +create_tool_item (EggAction *action) +{ + GtkWidget *image; + GtkWidget *ebox; + GtkWidget *item; + + item = (* EGG_ACTION_CLASS (parent_class)->create_tool_item) (action); + + ebox = gtk_event_box_new (); + image = gtk_image_new (); + gtk_container_add (GTK_CONTAINER (ebox), image); + gtk_container_set_border_width (GTK_CONTAINER (ebox), 2); + gtk_container_add (GTK_CONTAINER (item), ebox); + gtk_widget_show (image); + gtk_widget_show (ebox); + + g_object_set_data (G_OBJECT (item), "image", image); + + return item; +} + +static void +each_url_get_data_binder (EphyDragEachSelectedItemDataGet iteratee, + gpointer iterator_context, gpointer data) +{ + const char *location; + EphyTab *tab; + EphyWindow *window = EPHY_WINDOW(iterator_context); + + tab = ephy_window_get_active_tab (window); + location = ephy_tab_get_location (tab); + + iteratee (location, -1, -1, -1, -1, data); +} + +static void +favicon_drag_data_get_cb (GtkWidget *widget, + GdkDragContext *context, + GtkSelectionData *selection_data, + guint info, + guint32 time, + EphyWindow *window) +{ + g_assert (widget != NULL); + g_return_if_fail (context != NULL); + + ephy_dnd_drag_data_get (widget, context, selection_data, + info, time, window, each_url_get_data_binder); +} + +static void +ephy_favicon_action_sync_icon (EggAction *action, GParamSpec *pspec, + GtkWidget *proxy) +{ + EphyFaviconAction *fav_action = EPHY_FAVICON_ACTION (action); + char *url; + GtkWidget *image; + GdkPixbuf *pixbuf = NULL; + EphyFaviconCache *cache; + + cache = ephy_embed_shell_get_favicon_cache (EPHY_EMBED_SHELL (ephy_shell)); + + url = fav_action->priv->icon; + image = GTK_WIDGET (g_object_get_data (G_OBJECT (proxy), "image")); + + if (url) + { + pixbuf = ephy_favicon_cache_get (cache, url); + } + + if (pixbuf) + { + gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf); + } + else + { + gtk_image_set_from_stock (GTK_IMAGE (image), + GTK_STOCK_JUMP_TO, + GTK_ICON_SIZE_MENU); + } +} + +static void +connect_proxy (EggAction *action, GtkWidget *proxy) +{ + ephy_dnd_url_drag_source_set (proxy); + + g_signal_connect (proxy, + "drag_data_get", + G_CALLBACK (favicon_drag_data_get_cb), + EPHY_FAVICON_ACTION (action)->priv->window); + g_signal_connect_object (action, "notify::icon", + G_CALLBACK (ephy_favicon_action_sync_icon), + proxy, 0); + + (* EGG_ACTION_CLASS (parent_class)->connect_proxy) (action, proxy); +} + +static void +ephy_favicon_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyFaviconAction *fav; + + fav = EPHY_FAVICON_ACTION (object); + + switch (prop_id) + { + case PROP_WINDOW: + fav->priv->window = EPHY_WINDOW (g_value_get_object (value)); + break; + case PROP_ICON: + g_free (fav->priv->icon); + fav->priv->icon = g_strdup (g_value_get_string (value)); + g_object_notify(object, "icon"); + break; + } +} + +static void +ephy_favicon_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyFaviconAction *fav; + + fav = EPHY_FAVICON_ACTION (object); + + switch (prop_id) + { + case PROP_WINDOW: + g_value_set_object (value, fav->priv->window); + break; + case PROP_ICON: + g_value_set_object (value, fav->priv->icon); + break; + } +} + +static void +ephy_favicon_action_class_init (EphyFaviconActionClass *class) +{ + EggActionClass *action_class; + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->set_property = ephy_favicon_action_set_property; + object_class->get_property = ephy_favicon_action_get_property; + + parent_class = g_type_class_peek_parent (class); + action_class = EGG_ACTION_CLASS (class); + + action_class->toolbar_item_type = EGG_TYPE_TOOL_ITEM; + action_class->create_tool_item = create_tool_item; + action_class->connect_proxy = connect_proxy; + + g_object_class_install_property (object_class, + PROP_WINDOW, + g_param_spec_object ("window", + "Window", + "The window", + G_TYPE_OBJECT, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_ICON, + g_param_spec_string ("icon", + "Icon", + "The icon", + NULL, + G_PARAM_READWRITE)); +} + +static void +ephy_favicon_action_init (EphyFaviconAction *action) +{ + action->priv = g_new0 (EphyFaviconActionPrivate, 1); + action->priv->icon = NULL; +} diff --git a/src/ephy-favicon-action.h b/src/ephy-favicon-action.h new file mode 100644 index 000000000..31f6c3d82 --- /dev/null +++ b/src/ephy-favicon-action.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_FAVICON_ACTION_H +#define EPHY_FAVICON_ACTION_H + +#include <gtk/gtk.h> +#include <egg-action.h> + +#define EPHY_TYPE_FAVICON_ACTION (ephy_favicon_action_get_type ()) +#define EPHY_FAVICON_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_FAVICON_ACTION, EphyFaviconAction)) +#define EPHY_FAVICON_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_FAVICON_ACTION, EphyFaviconActionClass)) +#define EPHY_IS_FAVICON_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_FAVICON_ACTION)) +#define EPHY_IS_FAVICON_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EPHY_TYPE_FAVICON_ACTION)) +#define EPHY_FAVICON_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_FAVICON_ACTION, EphyFaviconActionClass)) + +typedef struct _EphyFaviconAction EphyFaviconAction; +typedef struct _EphyFaviconActionClass EphyFaviconActionClass; +typedef struct EphyFaviconActionPrivate EphyFaviconActionPrivate; + +struct _EphyFaviconAction +{ + EggAction parent; + EphyFaviconActionPrivate *priv; +}; + +struct _EphyFaviconActionClass +{ + EggActionClass parent_class; +}; + +GType ephy_favicon_action_get_type (void); + +#endif diff --git a/src/ephy-favorites-menu.c b/src/ephy-favorites-menu.c index b463663c2..8a557a7ad 100644 --- a/src/ephy-favorites-menu.c +++ b/src/ephy-favorites-menu.c @@ -23,7 +23,7 @@ #include "ephy-favorites-menu.h" #include "ephy-gobject-misc.h" #include "ephy-string.h" -#include "ephy-bonobo-extensions.h" +#include "egg-menu-merge.h" #include "ephy-marshal.h" #include "ephy-shell.h" #include "ephy-debug.h" @@ -39,9 +39,10 @@ */ struct _EphyFavoritesMenuPrivate { - gchar *path; EphyWindow *window; EphyBookmarks *bookmarks; + EggActionGroup *action_group; + guint ui_id; }; typedef struct @@ -109,18 +110,35 @@ ephy_favorites_menu_init (EphyFavoritesMenu *wrhm) wrhm->priv = p; wrhm->priv->bookmarks = ephy_shell_get_bookmarks (ephy_shell); + wrhm->priv->ui_id = -1; + wrhm->priv->action_group = NULL; } static void -ephy_favorites_menu_finalize_impl (GObject *o) +ephy_favorites_menu_clean (EphyFavoritesMenu *wrhm) { - EphyFavoritesMenu *wrhm = EPHY_FAVORITES_MENU (o); EphyFavoritesMenuPrivate *p = wrhm->priv; + EggMenuMerge *merge = EGG_MENU_MERGE (p->window->ui_merge); + + if (p->ui_id >= 0) + { + egg_menu_merge_remove_ui (merge, p->ui_id); + } - if (p->path) + if (p->action_group != NULL) { - g_free (p->path); + egg_menu_merge_remove_action_group (merge, p->action_group); + g_object_unref (p->action_group); } +} + +static void +ephy_favorites_menu_finalize_impl (GObject *o) +{ + EphyFavoritesMenu *wrhm = EPHY_FAVORITES_MENU (o); + EphyFavoritesMenuPrivate *p = wrhm->priv; + + ephy_favorites_menu_clean (wrhm); g_free (p); @@ -139,6 +157,7 @@ ephy_favorites_menu_set_property (GObject *object, { case PROP_EPHY_WINDOW: m->priv->window = g_value_get_object (value); + ephy_favorites_menu_rebuild (m); break; } } @@ -168,26 +187,6 @@ ephy_favorites_menu_new (EphyWindow *window) return ret; } -void -ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm, - const gchar *path) -{ - EphyFavoritesMenuPrivate *p; - - g_return_if_fail (EPHY_IS_FAVORITES_MENU (wrhm)); - g_return_if_fail (path != NULL); - - p = wrhm->priv; - - if (p->path) - { - g_free (p->path); - } - p->path = g_strdup (path); - - ephy_favorites_menu_update (wrhm); -} - static void ephy_favorites_menu_verb_cb (BonoboUIComponent *uic, FavoriteData *data, @@ -204,11 +203,7 @@ ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm) gint i; EphyNode *fav; GPtrArray *children; - BonoboUIComponent *uic = BONOBO_UI_COMPONENT (p->window->ui_component); - - if (!p->path) return; - - ephy_bonobo_clear_path (uic, p->path); + EggMenuMerge *merge = EGG_MENU_MERGE (p->window->ui_merge); LOG ("Rebuilding recent history menu") @@ -216,17 +211,22 @@ ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm) children = ephy_node_get_children (fav); xml = g_string_new (NULL); - g_string_append_printf (xml, "<placeholder name=\"wrhm%x\">\n", (guint) wrhm); + g_string_append (xml, "<Root><menu><submenu name=\"GoMenu\">" + "<placeholder name=\"GoFavorites\">"); + + p->action_group = egg_action_group_new ("FavoritesActions"); + egg_menu_merge_insert_action_group (merge, p->action_group, 0); for (i = 0; i < children->len; i++) { - char *verb = g_strdup_printf ("Wrhm%xn%d", (guint) wrhm, i); + char *verb = g_strdup_printf ("GoFav%d", i); char *title_s; const char *title; const char *url; xmlChar *label_x; EphyNode *child; FavoriteData *data; + EggAction *action; child = g_ptr_array_index (children, i); title = ephy_node_get_property_string (child, EPHY_NODE_BMK_PROP_TITLE); @@ -234,21 +234,32 @@ ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm) title_s = ephy_string_shorten (title, MAX_LABEL_LENGTH); label_x = xmlEncodeSpecialChars (NULL, title_s); + data = g_new0 (FavoriteData, 1); + data->window = wrhm->priv->window; + data->url = url; + + action = g_object_new (EGG_TYPE_ACTION, + "name", verb, + "label", label_x, + "tooltip", "Hello", + "stock_id", NULL, + NULL); + g_signal_connect_closure + (action, "activate", + g_cclosure_new (G_CALLBACK (ephy_favorites_menu_verb_cb), + data, + (GClosureNotify)g_free), + FALSE); + egg_action_group_add_action (p->action_group, action); + g_object_unref (action); + g_string_append (xml, "<menuitem name=\""); g_string_append (xml, verb); - g_string_append (xml, "\" label=\""); - g_string_append (xml, label_x); + g_string_append (xml, "Menu"); g_string_append (xml, "\" verb=\""); g_string_append (xml, verb); g_string_append (xml, "\"/>\n"); - data = g_new0 (FavoriteData, 1); - data->window = wrhm->priv->window; - data->url = url; - bonobo_ui_component_add_verb_full (uic, verb, g_cclosure_new - (G_CALLBACK (ephy_favorites_menu_verb_cb), data, - (GClosureNotify)g_free)); - xmlFree (label_x); g_free (title_s); g_free (verb); @@ -256,13 +267,16 @@ ephy_favorites_menu_rebuild (EphyFavoritesMenu *wrhm) ephy_node_thaw (fav); - g_string_append (xml, "</placeholder>\n"); + g_string_append (xml, "</placeholder></submenu></menu></Root>"); if (children->len > 0) { - bonobo_ui_component_set (uic, p->path, - xml->str, NULL); + GError *error = NULL; + + p->ui_id = egg_menu_merge_add_ui_from_string + (merge, xml->str, -1, &error); } + g_string_free (xml, TRUE); } diff --git a/src/ephy-favorites-menu.h b/src/ephy-favorites-menu.h index b76e8d2d8..228cbcef8 100644 --- a/src/ephy-favorites-menu.h +++ b/src/ephy-favorites-menu.h @@ -59,8 +59,5 @@ EphyFavoritesMenu *ephy_favorites_menu_new (EphyWindow *window); void ephy_favorites_menu_update (EphyFavoritesMenu *wrhm); -void ephy_favorites_menu_set_path (EphyFavoritesMenu *wrhm, - const gchar *path); - #endif diff --git a/src/ephy-location-action.c b/src/ephy-location-action.c new file mode 100644 index 000000000..07f7e6c2b --- /dev/null +++ b/src/ephy-location-action.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-location-action.h" +#include "ephy-location-entry.h" +#include "ephy-shell.h" +#include "ephy-debug.h" +#include "eggtoolitem.h" + +static void ephy_location_action_init (EphyLocationAction *action); +static void ephy_location_action_class_init (EphyLocationActionClass *class); + +enum +{ + GO_LOCATION, + LAST_SIGNAL +}; + +static GObjectClass *parent_class = NULL; + +static guint ephy_location_action_signals[LAST_SIGNAL] = { 0 }; + +GType +ephy_location_action_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EphyLocationActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ephy_location_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EphyLocationAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_location_action_init, + }; + + type = g_type_register_static (EGG_TYPE_ACTION, + "EphyLocationAction", + &type_info, 0); + } + return type; +} + +static GtkWidget * +create_tool_item (EggAction *action) +{ + GtkWidget *item; + GtkWidget *location; + + LOG ("Create location toolitem") + + item = (* EGG_ACTION_CLASS (parent_class)->create_tool_item) (action); + + location = ephy_location_entry_new (); + gtk_container_add (GTK_CONTAINER (item), location); + egg_tool_item_set_expandable (EGG_TOOL_ITEM (item), TRUE); + gtk_widget_show (location); + + LOG ("Create location toolitem: Done.") + + return item; +} + +static void +location_url_activate_cb (EphyLocationEntry *entry, + const char *content, + const char *target, + EphyLocationAction *action) +{ + EphyBookmarks *bookmarks; + LOG ("Location url activated") + bookmarks = ephy_shell_get_bookmarks (ephy_shell); + + if (!content) + { + LOG ("Go to %s", target); + g_signal_emit (action, + ephy_location_action_signals[GO_LOCATION], + 0, target); + } + else + { + char *url; + + url = ephy_bookmarks_solve_smart_url + (bookmarks, target, content); + g_return_if_fail (url != NULL); + LOG ("Go to %s", url); + g_signal_emit (action, + ephy_location_action_signals[GO_LOCATION], + 0, url); + g_free (url); + } +} + +static void +connect_proxy (EggAction *action, GtkWidget *proxy) +{ + EphyAutocompletion *ac = ephy_shell_get_autocompletion (ephy_shell); + EphyLocationEntry *e; + + LOG ("Connect location proxy") + + e = EPHY_LOCATION_ENTRY (GTK_BIN (proxy)->child); + ephy_location_entry_set_autocompletion (e, ac); + + g_signal_connect (e, "activated", + GTK_SIGNAL_FUNC(location_url_activate_cb), + action); + + (* EGG_ACTION_CLASS (parent_class)->connect_proxy) (action, proxy); +} + +static void +ephy_location_action_class_init (EphyLocationActionClass *class) +{ + EggActionClass *action_class; + GObjectClass *object_class = G_OBJECT_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + action_class = EGG_ACTION_CLASS (class); + + action_class->toolbar_item_type = EGG_TYPE_TOOL_ITEM; + action_class->create_tool_item = create_tool_item; + action_class->connect_proxy = connect_proxy; + + ephy_location_action_signals[GO_LOCATION] = + g_signal_new ("go_location", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (EphyLocationActionClass, go_location), + NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, + 1, + G_TYPE_STRING); +} + +static void +ephy_location_action_init (EphyLocationAction *action) +{ +} + +GtkWidget * +ephy_location_action_get_widget (EphyLocationAction *action) +{ + GSList *slist; + + slist = EGG_ACTION (action)->proxies; + + if (slist) + { + return GTK_BIN (slist->data)->child; + } + else + { + return NULL; + } +} + diff --git a/src/ephy-location-action.h b/src/ephy-location-action.h new file mode 100644 index 000000000..daa609aee --- /dev/null +++ b/src/ephy-location-action.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_LOCATION_ACTION_H +#define EPHY_LOCATION_ACTION_H + +#include <gtk/gtk.h> +#include <egg-action.h> + +#define EPHY_TYPE_LOCATION_ACTION (ephy_location_action_get_type ()) +#define EPHY_LOCATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_LOCATION_ACTION, EphyLocationAction)) +#define EPHY_LOCATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_LOCATION_ACTION, EphyLocationActionClass)) +#define EPHY_IS_LOCATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_LOCATION_ACTION)) +#define EPHY_IS_LOCATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EPHY_TYPE_LOCATION_ACTION)) +#define EPHY_LOCATION_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_LOCATION_ACTION, EphyLocationActionClass)) + +typedef struct _EphyLocationAction EphyLocationAction; +typedef struct _EphyLocationActionClass EphyLocationActionClass; + +struct _EphyLocationAction +{ + EggAction parent; +}; + +struct _EphyLocationActionClass +{ + EggActionClass parent_class; + + void (*go_location) (EphyLocationAction *action, char *location); +}; + +GType ephy_location_action_get_type (void); + +GtkWidget *ephy_location_action_get_widget (EphyLocationAction *action); + +#endif diff --git a/src/ephy-navigation-action.c b/src/ephy-navigation-action.c new file mode 100644 index 000000000..3aeaef386 --- /dev/null +++ b/src/ephy-navigation-action.c @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-navigation-action.h" +#include "ephy-arrow-toolbutton.h" +#include "ephy-window.h" +#include "ephy-debug.h" + +static void ephy_navigation_action_init (EphyNavigationAction *action); +static void ephy_navigation_action_class_init (EphyNavigationActionClass *class); + +static GObjectClass *parent_class = NULL; + +struct EphyNavigationActionPrivate +{ + EphyWindow *window; + EphyNavigationDirection direction; +}; + +enum +{ + PROP_0, + PROP_DIRECTION, + PROP_WINDOW +}; + +GType +ephy_navigation_action_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EphyNavigationActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ephy_navigation_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EphyNavigationAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_navigation_action_init, + }; + + type = g_type_register_static (EGG_TYPE_ACTION, + "EphyNavigationAction", + &type_info, 0); + } + return type; +} + +static GtkWidget * +new_history_menu_item (gchar *origtext, + const GdkPixbuf *ico) +{ + GtkWidget *item = gtk_image_menu_item_new (); + GtkWidget *hb = gtk_hbox_new (FALSE, 0); + GtkWidget *label = gtk_label_new (origtext); + + gtk_box_pack_start (GTK_BOX (hb), label, FALSE, FALSE, 0); + gtk_container_add (GTK_CONTAINER (item), hb); + + gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), + gtk_image_new_from_pixbuf ((GdkPixbuf *) ico)); + + gtk_widget_show_all (item); + + return item; +} + +static void +activate_back_or_forward_menu_item_cb (GtkWidget *menu, EphyWindow *window) +{ + EphyEmbed *embed; + int go_nth; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth"); + + ephy_embed_shistory_go_nth (embed, go_nth); +} + +static void +activate_up_menu_item_cb (GtkWidget *menu, EphyWindow *window) +{ + EphyEmbed *embed; + int go_nth; + GSList *l; + gchar *url; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth"); + + ephy_embed_get_go_up_list (embed, &l); + + url = g_slist_nth_data (l, go_nth); + if (url) + { + ephy_embed_load_url (embed, url); + } + + g_slist_foreach (l, (GFunc) g_free, NULL); + g_slist_free (l); +} + +static void +setup_back_or_forward_menu (EphyWindow *window, GtkMenuShell *ms, EphyNavigationDirection dir) +{ + int pos, count; + EphyEmbed *embed; + int start, end; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_shistory_get_pos (embed, &pos); + ephy_embed_shistory_count (embed, &count); + + if (count == 0) return; + + if (dir == EPHY_NAVIGATION_DIRECTION_BACK) + { + start = pos - 1; + end = -1; + } + else + { + start = pos + 1; + end = count; + } + + while (start != end) + { + char *title, *url; + GtkWidget *item; + ephy_embed_shistory_get_nth (embed, start, FALSE, &url, &title); + item = new_history_menu_item (title ? title : url, NULL); + gtk_menu_shell_append (ms, item); + g_object_set_data (G_OBJECT (item), "go_nth", GINT_TO_POINTER (start)); + g_signal_connect (item, "activate", + G_CALLBACK (activate_back_or_forward_menu_item_cb), window); + gtk_widget_show_all (item); + + g_free (url); + g_free (title); + + if (start < end) + { + start++; + } + else + { + start--; + } + } +} + +static void +setup_up_menu (EphyWindow *window, GtkMenuShell *ms) +{ + EphyEmbed *embed; + GSList *l; + GSList *li; + int count = 0; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_get_go_up_list (embed, &l); + + for (li = l; li; li = li->next) + { + char *url = li->data; + GtkWidget *item; + + item = new_history_menu_item (url, NULL); + gtk_menu_shell_append (ms, item); + g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (count)); + g_signal_connect (item, "activate", + G_CALLBACK (activate_up_menu_item_cb), window); + gtk_widget_show_all (item); + count ++; + } + + g_slist_foreach (l, (GFunc) g_free, NULL); + g_slist_free (l); +} + +static void +menu_activated_cb (EphyArrowToolButton *w, EphyNavigationAction *b) +{ + EphyNavigationActionPrivate *p = b->priv; + GtkMenuShell *ms = ephy_arrow_toolbutton_get_menu (w); + EphyWindow *win = b->priv->window; + GList *children; + GList *li; + + LOG ("Show navigation menu") + + children = gtk_container_get_children (GTK_CONTAINER (ms)); + for (li = children; li; li = li->next) + { + gtk_container_remove (GTK_CONTAINER (ms), li->data); + } + g_list_free (children); + + switch (p->direction) + { + case EPHY_NAVIGATION_DIRECTION_UP: + setup_up_menu (win, ms); + break; + case EPHY_NAVIGATION_DIRECTION_FORWARD: + case EPHY_NAVIGATION_DIRECTION_BACK: + setup_back_or_forward_menu (win, ms, p->direction); + break; + default: + g_assert_not_reached (); + break; + } +} + +static void +connect_proxy (EggAction *action, GtkWidget *proxy) +{ + LOG ("Connect navigation action proxy") + + g_signal_connect (proxy, "menu-activated", + G_CALLBACK (menu_activated_cb), action); + + (* EGG_ACTION_CLASS (parent_class)->connect_proxy) (action, proxy); +} + +static void +ephy_navigation_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphyNavigationAction *nav; + + nav = EPHY_NAVIGATION_ACTION (object); + + switch (prop_id) + { + case PROP_DIRECTION: + nav->priv->direction = g_value_get_int (value); + break; + case PROP_WINDOW: + nav->priv->window = EPHY_WINDOW (g_value_get_object (value)); + break; + } +} + +static void +ephy_navigation_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphyNavigationAction *nav; + + nav = EPHY_NAVIGATION_ACTION (object); + + switch (prop_id) + { + case PROP_DIRECTION: + g_value_set_int (value, nav->priv->direction); + break; + case PROP_WINDOW: + g_value_set_object (value, nav->priv->window); + break; + } +} + +static void +ephy_navigation_action_class_init (EphyNavigationActionClass *class) +{ + EggActionClass *action_class; + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->set_property = ephy_navigation_action_set_property; + object_class->get_property = ephy_navigation_action_get_property; + + parent_class = g_type_class_peek_parent (class); + action_class = EGG_ACTION_CLASS (class); + + action_class->toolbar_item_type = EPHY_ARROW_TOOLBUTTON_TYPE; + action_class->connect_proxy = connect_proxy; + + g_object_class_install_property (object_class, + PROP_DIRECTION, + g_param_spec_int ("direction", + "Direction", + "Direction", + 0, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + g_object_class_install_property (object_class, + PROP_WINDOW, + g_param_spec_object ("window", + "Window", + "The navigation window", + G_TYPE_OBJECT, + G_PARAM_READWRITE)); + +} + +static void +ephy_navigation_action_init (EphyNavigationAction *action) +{ + action->priv = g_new0 (EphyNavigationActionPrivate, 1); +} + + diff --git a/src/ephy-navigation-action.h b/src/ephy-navigation-action.h new file mode 100644 index 000000000..0e6c23dbe --- /dev/null +++ b/src/ephy-navigation-action.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_NAVIGATION_ACTION_H +#define EPHY_NAVIGATION_ACTION_H + +#include <gtk/gtk.h> +#include <egg-action.h> + +#define EPHY_TYPE_NAVIGATION_ACTION (ephy_navigation_action_get_type ()) +#define EPHY_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_NAVIGATION_ACTION, EphyNavigationAction)) +#define EPHY_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_NAVIGATION_ACTION, EphyNavigationActionClass)) +#define EPHY_IS_NAVIGATION_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_NAVIGATION_ACTION)) +#define EPHY_IS_NAVIGATION_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EPHY_TYPE_NAVIGATION_ACTION)) +#define EPHY_NAVIGATION_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_NAVIGATION_ACTION, EphyNavigationActionClass)) + +typedef struct _EphyNavigationAction EphyNavigationAction; +typedef struct _EphyNavigationActionClass EphyNavigationActionClass; +typedef struct EphyNavigationActionPrivate EphyNavigationActionPrivate; + +typedef enum +{ + EPHY_NAVIGATION_DIRECTION_UP, + EPHY_NAVIGATION_DIRECTION_BACK, + EPHY_NAVIGATION_DIRECTION_FORWARD +} EphyNavigationDirection; + +struct _EphyNavigationAction +{ + EggAction parent; + EphyNavigationActionPrivate *priv; +}; + +struct _EphyNavigationActionClass +{ + EggActionClass parent_class; +}; + +GType ephy_navigation_action_get_type (void); + +#endif diff --git a/src/ephy-navigation-button.c b/src/ephy-navigation-button.c deleted file mode 100644 index d0d80af7f..000000000 --- a/src/ephy-navigation-button.c +++ /dev/null @@ -1,612 +0,0 @@ -/* - * Copyright (C) 2002 Ricardo Fernández Pascual - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ephy-gobject-misc.h" -#include "ephy-marshal.h" -#include "ephy-tb-button.h" -#include "ephy-gui.h" -#include "ephy-string.h" -#include "ephy-navigation-button.h" -#include "ephy-debug.h" - -#include <gtk/gtkstock.h> -#include <string.h> -#include <libgnome/gnome-i18n.h> - -/** - * Private data - */ -struct _EphyNavigationButtonPrivate -{ - EphyTbButton *widget; - EphyNavigationDirection direction; - gboolean show_arrow; - gboolean sensitive; -}; - -enum -{ - TOOLBAR_ITEM_STYLE_PROP, - TOOLBAR_ITEM_ORIENTATION_PROP, - TOOLBAR_ITEM_WANT_LABEL_PROP -}; - -/** - * Private functions, only availble from this file - */ -static void ephy_navigation_button_class_init (EphyNavigationButtonClass *klass); -static void ephy_navigation_button_init (EphyNavigationButton *tb); -static void ephy_navigation_button_finalize_impl (GObject *o); -static GtkWidget * ephy_navigation_button_get_widget_impl (EphyTbItem *i); -static GdkPixbuf * ephy_navigation_button_get_icon_impl (EphyTbItem *i); -static gchar * ephy_navigation_button_get_name_human_impl (EphyTbItem *i); -static gchar * ephy_navigation_button_to_string_impl (EphyTbItem *i); -static EphyTbItem * ephy_navigation_button_clone_impl (EphyTbItem *i); -static void ephy_navigation_button_parse_properties_impl (EphyTbItem *i, const gchar *props); -static void ephy_navigation_button_menu_activated_cb (EphyTbButton *w, EphyNavigationButton *b); -static void ephy_navigation_button_clicked_cb (GtkWidget *w, EphyNavigationButton *b); - - -static gpointer ephy_tb_item_class; - -/** - * TbiZoom object - */ - -MAKE_GET_TYPE (ephy_navigation_button, "EphyNavigationButton", EphyNavigationButton, - ephy_navigation_button_class_init, - ephy_navigation_button_init, EPHY_TYPE_TBI); - -static void -ephy_navigation_button_class_init (EphyNavigationButtonClass *klass) -{ - G_OBJECT_CLASS (klass)->finalize = ephy_navigation_button_finalize_impl; - - EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_navigation_button_get_widget_impl; - EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_navigation_button_get_icon_impl; - EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_navigation_button_get_name_human_impl; - EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_navigation_button_to_string_impl; - EPHY_TB_ITEM_CLASS (klass)->clone = ephy_navigation_button_clone_impl; - EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_navigation_button_parse_properties_impl; - - ephy_tb_item_class = g_type_class_peek_parent (klass); -} - -static void -ephy_navigation_button_init (EphyNavigationButton *tbi) -{ - EphyNavigationButtonPrivate *p = g_new0 (EphyNavigationButtonPrivate, 1); - tbi->priv = p; - - p->direction = EPHY_NAVIGATION_DIRECTION_UP; - p->show_arrow = TRUE; - p->sensitive = TRUE; -} - -EphyNavigationButton * -ephy_navigation_button_new (void) -{ - EphyNavigationButton *ret = g_object_new (EPHY_TYPE_NAVIGATION_BUTTON, NULL); - return ret; -} - -static void -ephy_navigation_button_finalize_impl (GObject *o) -{ - EphyNavigationButton *it = EPHY_NAVIGATION_BUTTON (o); - EphyNavigationButtonPrivate *p = it->priv; - - if (p->widget) - { - g_object_unref (p->widget); - } - - g_free (p); - - LOG ("EphyNavigationButton finalized") - - G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); -} - -static void -ephy_navigation_button_setup_widget (EphyNavigationButton *b) -{ - EphyNavigationButtonPrivate *p = b->priv; - const gchar *label; - const gchar *tip; - gboolean prio; - - if (!p->widget) - { - ephy_navigation_button_get_widget_impl (EPHY_TB_ITEM (b)); - } - g_assert (EPHY_IS_TB_BUTTON (p->widget)); - - switch (p->direction) - { - case EPHY_NAVIGATION_DIRECTION_UP: - label = "gtk-go-up"; - tip = _("Go up"); - prio = FALSE; - break; - case EPHY_NAVIGATION_DIRECTION_BACK: - label = "gtk-go-back"; - tip = _("Go back"); - prio = TRUE; - break; - case EPHY_NAVIGATION_DIRECTION_FORWARD: - label = "gtk-go-forward"; - tip = _("Go forward"); - prio = FALSE; - break; - default: - g_assert_not_reached (); - label = NULL; - tip = NULL; - prio = FALSE; - break; - } - - ephy_tb_button_set_label (p->widget, label); - ephy_tb_button_set_tooltip_text (p->widget, tip); - ephy_tb_button_set_priority (p->widget, prio); - ephy_tb_button_set_show_arrow (p->widget, p->show_arrow); - ephy_tb_button_set_sensitivity (p->widget, p->sensitive); -} - -static GtkWidget * -ephy_navigation_button_get_widget_impl (EphyTbItem *i) -{ - EphyNavigationButton *iz = EPHY_NAVIGATION_BUTTON (i); - EphyNavigationButtonPrivate *p = iz->priv; - - if (!p->widget) - { - p->widget = ephy_tb_button_new (); - g_object_ref (p->widget); - ephy_tb_button_set_use_stock (p->widget, TRUE); - ephy_tb_button_set_enable_menu (p->widget, TRUE); - - ephy_navigation_button_setup_widget (iz); - - gtk_widget_show (GTK_WIDGET (p->widget)); - - g_signal_connect (p->widget, "menu-activated", - G_CALLBACK (ephy_navigation_button_menu_activated_cb), i); - g_signal_connect (ephy_tb_button_get_button (p->widget), "clicked", - G_CALLBACK (ephy_navigation_button_clicked_cb), i); - } - - return GTK_WIDGET (p->widget); -} - -static GdkPixbuf * -ephy_navigation_button_get_icon_impl (EphyTbItem *i) -{ - EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv; - - static GdkPixbuf *pb_up = NULL; - static GdkPixbuf *pb_back = NULL; - static GdkPixbuf *pb_forward = NULL; - - if (!pb_up) - { - /* what's the easier way? */ - GtkWidget *b = gtk_button_new (); - pb_up = gtk_widget_render_icon (b, - GTK_STOCK_GO_UP, - GTK_ICON_SIZE_SMALL_TOOLBAR, - NULL); - pb_back = gtk_widget_render_icon (b, - GTK_STOCK_GO_BACK, - GTK_ICON_SIZE_SMALL_TOOLBAR, - NULL); - pb_forward = gtk_widget_render_icon (b, - GTK_STOCK_GO_FORWARD, - GTK_ICON_SIZE_SMALL_TOOLBAR, - NULL); - gtk_widget_destroy (b); - } - - switch (p->direction) - { - case EPHY_NAVIGATION_DIRECTION_BACK: - return g_object_ref (pb_back); - break; - case EPHY_NAVIGATION_DIRECTION_FORWARD: - return g_object_ref (pb_forward); - break; - case EPHY_NAVIGATION_DIRECTION_UP: - return g_object_ref (pb_up); - break; - default: - g_assert_not_reached (); - return NULL; - } -} - -static gchar * -ephy_navigation_button_get_name_human_impl (EphyTbItem *i) -{ - EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv; - const gchar *ret; - - switch (p->direction) - { - case EPHY_NAVIGATION_DIRECTION_BACK: - ret = p->show_arrow - ? _("Back (with menu)") - : _("Back"); - break; - case EPHY_NAVIGATION_DIRECTION_FORWARD: - ret = p->show_arrow - ? _("Forward (with menu)") - : _("Forward"); - break; - case EPHY_NAVIGATION_DIRECTION_UP: - ret = p->show_arrow - ? _("Up (with menu)") - : _("Up"); - break; - default: - g_assert_not_reached (); - ret = "Error: unexpected direction"; - break; - } - - return g_strdup (ret); -} - -static gchar * -ephy_navigation_button_to_string_impl (EphyTbItem *i) -{ - EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv; - - /* if it had any properties, the string should include them */ - const char *sdir; - - switch (p->direction) - { - case EPHY_NAVIGATION_DIRECTION_BACK: - sdir = "back"; - break; - case EPHY_NAVIGATION_DIRECTION_FORWARD: - sdir = "forward"; - break; - case EPHY_NAVIGATION_DIRECTION_UP: - sdir = "up"; - break; - default: - g_assert_not_reached (); - sdir = "unknown"; - } - - return g_strdup_printf ("%s=navigation_button(direction=%s,arrow=%s)", - i->id, sdir, p->show_arrow ? "TRUE" : "FALSE"); -} - -static EphyTbItem * -ephy_navigation_button_clone_impl (EphyTbItem *i) -{ - EphyTbItem *ret = EPHY_TB_ITEM (ephy_navigation_button_new ()); - EphyNavigationButtonPrivate *p = EPHY_NAVIGATION_BUTTON (i)->priv; - - ephy_tb_item_set_id (ret, i->id); - - ephy_navigation_button_set_direction (EPHY_NAVIGATION_BUTTON (ret), p->direction); - ephy_navigation_button_set_show_arrow (EPHY_NAVIGATION_BUTTON (ret), p->show_arrow); - - return ret; -} - -static void -ephy_navigation_button_parse_properties_impl (EphyTbItem *it, const gchar *props) -{ - EphyNavigationButton *b = EPHY_NAVIGATION_BUTTON (it); - - /* we have two properties, the direction and the arrow */ - const gchar *direc_prop; - const gchar *show_arrow_prop; - - direc_prop = strstr (props, "direction="); - if (direc_prop) - { - direc_prop += strlen ("direction="); - if (!strncmp (direc_prop, "back", 4)) - { - ephy_navigation_button_set_direction (b, EPHY_NAVIGATION_DIRECTION_BACK); - } - else if (!strncmp (direc_prop, "forward", 4)) - { - ephy_navigation_button_set_direction (b, EPHY_NAVIGATION_DIRECTION_FORWARD); - } - else if (!strncmp (direc_prop, "up", 2)) - { - ephy_navigation_button_set_direction (b, EPHY_NAVIGATION_DIRECTION_UP); - } - } - - show_arrow_prop = strstr (props, "arrow="); - if (show_arrow_prop) - { - show_arrow_prop += strlen ("arrow="); - if (show_arrow_prop[0] == 'T') - { - ephy_navigation_button_set_show_arrow (b, TRUE); - } - else - { - ephy_navigation_button_set_show_arrow (b, FALSE); - } - } -} - - -void -ephy_navigation_button_set_direction (EphyNavigationButton *b, - EphyNavigationDirection d) -{ - EphyNavigationButtonPrivate *p = b->priv; - p->direction = d; - ephy_navigation_button_setup_widget (b); -} - -void -ephy_navigation_button_set_show_arrow (EphyNavigationButton *b, - gboolean value) -{ - EphyNavigationButtonPrivate *p = b->priv; - p->show_arrow = value; - if (p->widget) - { - ephy_tb_button_set_show_arrow (p->widget, p->show_arrow); - } - else - { - ephy_navigation_button_get_widget_impl (EPHY_TB_ITEM (b)); - } -} - -EphyNavigationDirection -ephy_navigation_button_get_direction (EphyNavigationButton *b) -{ - return b->priv->direction; -} - -void -ephy_navigation_button_set_sensitive (EphyNavigationButton *b, gboolean s) -{ - EphyNavigationButtonPrivate *p = b->priv; - p->sensitive = s; - if (p->widget) - { - ephy_tb_button_set_sensitivity (p->widget, s); - } - else - { - ephy_navigation_button_get_widget_impl (EPHY_TB_ITEM (b)); - } -} - -static void -ephy_navigation_button_clicked_cb (GtkWidget *w, EphyNavigationButton *b) -{ - EphyNavigationButtonPrivate *p = b->priv; - EphyWindow *window; - EphyEmbed *embed; - - window = ephy_tbi_get_window (EPHY_TBI (b)); - g_return_if_fail (window != NULL); - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - switch (p->direction) - { - case EPHY_NAVIGATION_DIRECTION_UP: - ephy_embed_go_up (embed); - break; - case EPHY_NAVIGATION_DIRECTION_BACK: - ephy_embed_go_back (embed); - break; - case EPHY_NAVIGATION_DIRECTION_FORWARD: - ephy_embed_go_forward (embed); - break; - default: - g_assert_not_reached (); - break; - } -} - -/* TODO: clean all this, it came from toolbar.c and is messy */ - -static GtkWidget * -new_history_menu_item (gchar *origtext, - const GdkPixbuf *ico) -{ - GtkWidget *item = gtk_image_menu_item_new (); - GtkWidget *hb = gtk_hbox_new (FALSE, 0); - GtkWidget *label = gtk_label_new (origtext); - - gtk_box_pack_start (GTK_BOX (hb), label, FALSE, FALSE, 0); - gtk_container_add (GTK_CONTAINER (item), hb); - - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), - gtk_image_new_from_pixbuf ((GdkPixbuf *) ico)); - - gtk_widget_show_all (item); - - return item; -} - -static void -activate_back_or_forward_menu_item_cb (GtkWidget *menu, EphyWindow *window) -{ - EphyEmbed *embed; - int go_nth; - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth"); - - ephy_embed_shistory_go_nth (embed, go_nth); -} - -static void -activate_up_menu_item_cb (GtkWidget *menu, EphyWindow *window) -{ - EphyEmbed *embed; - int go_nth; - GSList *l; - gchar *url; - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - go_nth = (int)g_object_get_data (G_OBJECT(menu), "go_nth"); - - ephy_embed_get_go_up_list (embed, &l); - - url = g_slist_nth_data (l, go_nth); - if (url) - { - ephy_embed_load_url (embed, url); - } - - g_slist_foreach (l, (GFunc) g_free, NULL); - g_slist_free (l); -} - -static void -setup_back_or_forward_menu (EphyWindow *window, GtkMenuShell *ms, EphyNavigationDirection dir) -{ - int pos, count; - EphyEmbed *embed; - int start, end; - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - ephy_embed_shistory_get_pos (embed, &pos); - ephy_embed_shistory_count (embed, &count); - - if (count == 0) return; - - if (dir == EPHY_NAVIGATION_DIRECTION_BACK) - { - start = pos - 1; - end = -1; - } - else - { - start = pos + 1; - end = count; - } - - while (start != end) - { - char *title, *url; - GtkWidget *item; - ephy_embed_shistory_get_nth (embed, start, FALSE, &url, &title); - item = new_history_menu_item (title ? title : url, NULL); - gtk_menu_shell_append (ms, item); - g_object_set_data (G_OBJECT (item), "go_nth", GINT_TO_POINTER (start)); - g_signal_connect (item, "activate", - G_CALLBACK (activate_back_or_forward_menu_item_cb), window); - gtk_widget_show_all (item); - - g_free (url); - g_free (title); - - if (start < end) - { - start++; - } - else - { - start--; - } - } -} - -static void -setup_up_menu (EphyWindow *window, GtkMenuShell *ms) -{ - EphyEmbed *embed; - GSList *l; - GSList *li; - int count = 0; - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - ephy_embed_get_go_up_list (embed, &l); - - for (li = l; li; li = li->next) - { - char *url = li->data; - GtkWidget *item; - - item = new_history_menu_item (url, NULL); - gtk_menu_shell_append (ms, item); - g_object_set_data (G_OBJECT(item), "go_nth", GINT_TO_POINTER (count)); - g_signal_connect (item, "activate", - G_CALLBACK (activate_up_menu_item_cb), window); - gtk_widget_show_all (item); - count ++; - } - - g_slist_foreach (l, (GFunc) g_free, NULL); - g_slist_free (l); -} - -static void -ephy_navigation_button_menu_activated_cb (EphyTbButton *w, EphyNavigationButton *b) -{ - EphyNavigationButtonPrivate *p = b->priv; - GtkMenuShell *ms = ephy_tb_button_get_menu (p->widget); - EphyWindow *win = ephy_tbi_get_window (EPHY_TBI (b)); - GList *children; - GList *li; - - children = gtk_container_get_children (GTK_CONTAINER (ms)); - for (li = children; li; li = li->next) - { - gtk_container_remove (GTK_CONTAINER (ms), li->data); - } - g_list_free (children); - - switch (p->direction) - { - case EPHY_NAVIGATION_DIRECTION_UP: - setup_up_menu (win, ms); - break; - case EPHY_NAVIGATION_DIRECTION_FORWARD: - case EPHY_NAVIGATION_DIRECTION_BACK: - setup_back_or_forward_menu (win, ms, p->direction); - break; - default: - g_assert_not_reached (); - break; - } -} diff --git a/src/ephy-navigation-button.h b/src/ephy-navigation-button.h deleted file mode 100644 index 036ec6d7e..000000000 --- a/src/ephy-navigation-button.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2002 Ricardo Fernández Pascual - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef EPHY_NAVIGATION_BUTTON_H -#define EPHY_NAVIGATION_BUTTON_H - -#include "ephy-tbi.h" - -G_BEGIN_DECLS - -/* object forward declarations */ - -typedef struct _EphyNavigationButton EphyNavigationButton; -typedef struct _EphyNavigationButtonClass EphyNavigationButtonClass; -typedef struct _EphyNavigationButtonPrivate EphyNavigationButtonPrivate; - -/** - * TbiZoom object - */ - -#define EPHY_TYPE_NAVIGATION_BUTTON (ephy_navigation_button_get_type()) -#define EPHY_NAVIGATION_BUTTON(object) (G_TYPE_CHECK_INSTANCE_CAST((object), \ - EPHY_TYPE_NAVIGATION_BUTTON, EphyNavigationButton)) -#define EPHY_NAVIGATION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_NAVIGATION_BUTTON,\ - EphyNavigationButtonClass)) -#define EPHY_IS_NAVIGATION_BUTTON(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), \ - EPHY_TYPE_NAVIGATION_BUTTON)) -#define EPHY_IS_NAVIGATION_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_NAVIGATION_BUTTON)) -#define EPHY_NAVIGATION_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_NAVIGATION_BUTTON,\ - EphyNavigationButtonClass)) - -typedef enum -{ - EPHY_NAVIGATION_DIRECTION_UP, - EPHY_NAVIGATION_DIRECTION_BACK, - EPHY_NAVIGATION_DIRECTION_FORWARD -} EphyNavigationDirection; - -struct _EphyNavigationButtonClass -{ - EphyTbiClass parent_class; -}; - -/* Remember: fields are public read-only */ -struct _EphyNavigationButton -{ - EphyTbi parent_object; - EphyNavigationButtonPrivate *priv; -}; - -/* this class is abstract */ - -GType ephy_navigation_button_get_type (void); -EphyNavigationButton * ephy_navigation_button_new (void); -void ephy_navigation_button_set_direction (EphyNavigationButton *a, - EphyNavigationDirection d); -void ephy_navigation_button_set_show_arrow (EphyNavigationButton *b, - gboolean value); -EphyNavigationDirection ephy_navigation_button_get_direction (EphyNavigationButton *b); -void ephy_navigation_button_set_sensitive (EphyNavigationButton *b, gboolean s); - -G_END_DECLS - -#endif diff --git a/src/ephy-shell.c b/src/ephy-shell.c index feeb4d388..11954632d 100644 --- a/src/ephy-shell.c +++ b/src/ephy-shell.c @@ -509,6 +509,7 @@ ephy_shell_get_autocompletion (EphyShell *gs) }; EphyHistory *gh = ephy_embed_shell_get_global_history (EPHY_EMBED_SHELL (gs)); + EphyBookmarks *bmk = ephy_shell_get_bookmarks (gs); EphyFilesystemAutocompletion *fa = ephy_filesystem_autocompletion_new (); p->autocompletion = ephy_autocompletion_new (); ephy_autocompletion_set_prefixes (p->autocompletion, prefixes); @@ -518,7 +519,7 @@ ephy_shell_get_autocompletion (EphyShell *gs) ephy_autocompletion_add_source (p->autocompletion, EPHY_AUTOCOMPLETION_SOURCE (fa)); ephy_autocompletion_add_source (p->autocompletion, - EPHY_AUTOCOMPLETION_SOURCE (gs->priv->bookmarks)); + EPHY_AUTOCOMPLETION_SOURCE (bmk)); g_object_unref (gh); g_object_unref (fa); diff --git a/src/ephy-spinner-action.c b/src/ephy-spinner-action.c new file mode 100644 index 000000000..3e990f49b --- /dev/null +++ b/src/ephy-spinner-action.c @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "ephy-spinner-action.h" +#include "ephy-spinner.h" +#include "eggtoolitem.h" + +static void ephy_spinner_action_init (EphySpinnerAction *action); +static void ephy_spinner_action_class_init (EphySpinnerActionClass *class); + +struct EphySpinnerActionPrivate +{ + gboolean throbbing; +}; + +enum +{ + PROP_0, + PROP_THROBBING +}; + +static GObjectClass *parent_class = NULL; + +GType +ephy_spinner_action_get_type (void) +{ + static GtkType type = 0; + + if (!type) + { + static const GTypeInfo type_info = + { + sizeof (EphySpinnerActionClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) ephy_spinner_action_class_init, + (GClassFinalizeFunc) NULL, + NULL, + sizeof (EphySpinnerAction), + 0, /* n_preallocs */ + (GInstanceInitFunc) ephy_spinner_action_init, + }; + + type = g_type_register_static (EGG_TYPE_ACTION, + "EphySpinnerAction", + &type_info, 0); + } + return type; +} + +static void +ephy_spinner_action_sync_throbbing (EggAction *action, GParamSpec *pspec, + GtkWidget *proxy) +{ + EphySpinner *spinner; + + spinner = EPHY_SPINNER (g_object_get_data (G_OBJECT (proxy), "spinner")); + + if (EPHY_SPINNER_ACTION (action)->priv->throbbing) + { + ephy_spinner_start (spinner); + } + else + { + ephy_spinner_stop (spinner); + } +} + +static GtkWidget * +create_tool_item (EggAction *action) +{ + GtkWidget *item; + GtkWidget *spinner; + GtkWidget *button; + + item = (* EGG_ACTION_CLASS (parent_class)->create_tool_item) (action); + + button = gtk_button_new (); + gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); + gtk_widget_show (button); + gtk_container_add (GTK_CONTAINER (item), button); + spinner = ephy_spinner_new (); + ephy_spinner_set_small_mode (EPHY_SPINNER (spinner), TRUE); + gtk_container_add (GTK_CONTAINER (button), spinner); + egg_tool_item_set_pack_end (EGG_TOOL_ITEM (item), TRUE); + egg_tool_item_set_homogeneous (EGG_TOOL_ITEM (item), FALSE); + gtk_widget_show (spinner); + g_object_set_data (G_OBJECT (item), "spinner", spinner); + + return item; +} + +static void +connect_proxy (EggAction *action, GtkWidget *proxy) +{ + g_signal_connect_object (action, "notify::throbbing", + G_CALLBACK (ephy_spinner_action_sync_throbbing), + proxy, 0); + + (* EGG_ACTION_CLASS (parent_class)->connect_proxy) (action, proxy); +} +static void +ephy_spinner_action_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + EphySpinnerAction *spin; + + spin = EPHY_SPINNER_ACTION (object); + + switch (prop_id) + { + case PROP_THROBBING: + spin->priv->throbbing = g_value_get_boolean (value); + g_object_notify(object, "throbbing"); + break; + } +} + +static void +ephy_spinner_action_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + EphySpinnerAction *spin; + + spin = EPHY_SPINNER_ACTION (object); + + switch (prop_id) + { + case PROP_THROBBING: + g_value_set_boolean (value, spin->priv->throbbing); + break; + } +} + +static void +ephy_spinner_action_class_init (EphySpinnerActionClass *class) +{ + EggActionClass *action_class; + GObjectClass *object_class = G_OBJECT_CLASS (class); + + parent_class = g_type_class_peek_parent (class); + action_class = EGG_ACTION_CLASS (class); + + action_class->toolbar_item_type = EGG_TYPE_TOOL_ITEM; + action_class->create_tool_item = create_tool_item; + action_class->connect_proxy = connect_proxy; + + object_class->set_property = ephy_spinner_action_set_property; + object_class->get_property = ephy_spinner_action_get_property; + + g_object_class_install_property (object_class, + PROP_THROBBING, + g_param_spec_boolean ("throbbing", + "Throbbing", + "Throbbing", + FALSE, + G_PARAM_READWRITE)); +} + +static void +ephy_spinner_action_init (EphySpinnerAction *action) +{ + action->priv = g_new0 (EphySpinnerActionPrivate, 1); +} diff --git a/src/ephy-spinner-action.h b/src/ephy-spinner-action.h new file mode 100644 index 000000000..adb9d76c2 --- /dev/null +++ b/src/ephy-spinner-action.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2003 Marco Pesenti Gritti + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EPHY_SPINNER_ACTION_H +#define EPHY_SPINNER_ACTION_H + +#include <gtk/gtk.h> +#include <egg-action.h> + +#define EPHY_TYPE_SPINNER_ACTION (ephy_spinner_action_get_type ()) +#define EPHY_SPINNER_ACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EPHY_TYPE_SPINNER_ACTION, EphySpinnerAction)) +#define EPHY_SPINNER_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_SPINNER_ACTION, EphySpinnerActionClass)) +#define EPHY_IS_SPINNER_ACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_SPINNER_ACTION)) +#define EPHY_IS_SPINNER_ACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), EPHY_TYPE_SPINNER_ACTION)) +#define EPHY_SPINNER_ACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_SPINNER_ACTION, EphySpinnerActionClass)) + +typedef struct _EphySpinnerAction EphySpinnerAction; +typedef struct _EphySpinnerActionClass EphySpinnerActionClass; +typedef struct EphySpinnerActionPrivate EphySpinnerActionPrivate; + +struct _EphySpinnerAction +{ + EggAction parent; + EphySpinnerActionPrivate *priv; +}; + +struct _EphySpinnerActionClass +{ + EggActionClass parent_class; +}; + +GType ephy_spinner_action_get_type (void); + +#endif diff --git a/src/ephy-tab.c b/src/ephy-tab.c index 7561bb476..98f04fad1 100644 --- a/src/ephy-tab.c +++ b/src/ephy-tab.c @@ -22,11 +22,11 @@ #include "ephy-tab.h" #include "ephy-shell.h" -#include "ephy-embed-popup-bw.h" #include "eel-gconf-extensions.h" #include "ephy-prefs.h" #include "ephy-embed-prefs.h" #include "ephy-debug.h" +#include "egg-menu-merge.h" #include <bonobo/bonobo-i18n.h> #include <libgnomevfs/gnome-vfs-uri.h> @@ -39,12 +39,15 @@ #include <gtk/gtkiconfactory.h> #include <gtk/gtkstyle.h> #include <gtk/gtkselection.h> +#include <gtk/gtkmain.h> +#include <gtk/gtkmenu.h> #include <string.h> struct EphyTabPrivate { EphyEmbed *embed; EphyWindow *window; + EphyEmbedEvent *event; gboolean is_active; TabLoadStatus load_status; char status_message[255]; @@ -195,6 +198,7 @@ ephy_tab_init (EphyTab *tab) tab->priv->embed = ephy_embed_new (G_OBJECT(shell)); tab->priv->window = NULL; + tab->priv->event = NULL; tab->priv->is_active = FALSE; *tab->priv->status_message = '\0'; *tab->priv->link_message = '\0'; @@ -280,6 +284,11 @@ ephy_tab_finalize (GObject *object) g_idle_remove_by_data (tab->priv->embed); + if (tab->priv->event) + { + g_object_unref (tab->priv->event); + } + g_free (tab->priv); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -346,6 +355,12 @@ ephy_tab_get_window (EphyTab *tab) return tab->priv->window; } +EphyEmbedEvent * +ephy_tab_get_event (EphyTab *tab) +{ + return tab->priv->event; +} + static void ephy_tab_update_color (EphyTab *tab) { @@ -813,24 +828,68 @@ ephy_tab_dom_mouse_click_cb (EphyEmbed *embed, } static void +ephy_tab_set_event (EphyTab *tab, + EphyEmbedEvent *event) +{ + if (tab->priv->event) g_object_unref (tab->priv->event); + g_object_ref (event); + tab->priv->event = event; +} + +static void ephy_tab_show_embed_popup (EphyTab *tab, EphyEmbedEvent *event) { - EphyEmbedPopup *popup; + EmbedEventContext context; + const char *popup; + const GValue *value; + gboolean framed; EphyWindow *window; - EphyEmbed *embed; + char *path; + GtkWidget *widget; window = ephy_tab_get_window (tab); - embed = ephy_tab_get_embed (tab); - popup = EPHY_EMBED_POPUP (ephy_window_get_popup_factory (window)); - ephy_embed_popup_set_event (popup, event); - ephy_embed_popup_show (popup, embed); + ephy_embed_event_get_property (event, "framed_page", &value); + framed = g_value_get_int (value); + + ephy_embed_event_get_context (event, &context); + + if ((context & EMBED_CONTEXT_LINK) && + (context & EMBED_CONTEXT_IMAGE)) + { + popup = "EphyImageLinkPopup"; + } + else if (context & EMBED_CONTEXT_LINK) + { + popup = "EphyLinkPopup"; + } + else if (context & EMBED_CONTEXT_IMAGE) + { + popup = "EphyImagePopup"; + } + else + { + popup = framed ? "EphyFramedDocumentPopup" : + "EphyDocumentPopup"; + } + + path = g_strconcat ("/popups/", popup, NULL); + g_print (path); + widget = egg_menu_merge_get_widget (EGG_MENU_MERGE (window->ui_merge), + path); + g_free (path); + + g_return_if_fail (widget != NULL); + + ephy_tab_set_event (tab, event); + gtk_menu_popup (GTK_MENU (widget), NULL, NULL, NULL, NULL, 2, + gtk_get_current_event_time ()); } static gint ephy_tab_dom_mouse_down_cb (EphyEmbed *embed, - EphyEmbedEvent *event, - EphyTab *tab) + EphyEmbedEvent *event, + EphyTab *tab) { EphyWindow *window; int button; diff --git a/src/ephy-tab.h b/src/ephy-tab.h index fe679f553..82f6d16a6 100644 --- a/src/ephy-tab.h +++ b/src/ephy-tab.h @@ -102,6 +102,8 @@ void ephy_tab_get_size (EphyTab *tab, void ephy_tab_update_control (EphyTab *tab, TabControlID id); +EphyEmbedEvent *ephy_tab_get_event (EphyTab *tab); + G_END_DECLS #endif diff --git a/src/ephy-tbi.c b/src/ephy-tbi.c deleted file mode 100644 index 4a8993c46..000000000 --- a/src/ephy-tbi.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (C) 2002 Ricardo Fernández Pascual - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "ephy-gobject-misc.h" -#include "ephy-marshal.h" -#include "ephy-bonobo-extensions.h" -#include "ephy-tbi.h" -#include "ephy-debug.h" - -#include <string.h> -#include <libgnome/gnome-i18n.h> - -/** - * Private data - */ -struct _EphyTbiPrivate -{ -}; - -/** - * Private functions, only availble from this file - */ -static void ephy_tbi_class_init (EphyTbiClass *klass); -static void ephy_tbi_init (EphyTbi *tb); -static void ephy_tbi_finalize_impl (GObject *o); -static GtkWidget * ephy_tbi_get_widget_impl (EphyTbItem *i); -static GdkPixbuf * ephy_tbi_get_icon_impl (EphyTbItem *i); -static gchar * ephy_tbi_get_name_human_impl (EphyTbItem *i); -static gchar * ephy_tbi_to_string_impl (EphyTbItem *i); -static gboolean ephy_tbi_is_unique_impl (EphyTbItem *i); -static EphyTbItem * ephy_tbi_clone_impl (EphyTbItem *i); -static void ephy_tbi_parse_properties_impl (EphyTbItem *i, const gchar *props); -static void ephy_tbi_add_to_bonobo_tb_impl (EphyTbItem *i, - BonoboUIComponent *ui, - const char *container_path, - guint index); - - -static gpointer ephy_tb_item_class; - -/** - * EphyTbi object - */ - -MAKE_GET_TYPE (ephy_tbi, "EphyTbi", EphyTbi, ephy_tbi_class_init, - ephy_tbi_init, EPHY_TYPE_TB_ITEM); - -static void -ephy_tbi_class_init (EphyTbiClass *klass) -{ - G_OBJECT_CLASS (klass)->finalize = ephy_tbi_finalize_impl; - - EPHY_TB_ITEM_CLASS (klass)->get_widget = ephy_tbi_get_widget_impl; - EPHY_TB_ITEM_CLASS (klass)->get_icon = ephy_tbi_get_icon_impl; - EPHY_TB_ITEM_CLASS (klass)->get_name_human = ephy_tbi_get_name_human_impl; - EPHY_TB_ITEM_CLASS (klass)->to_string = ephy_tbi_to_string_impl; - EPHY_TB_ITEM_CLASS (klass)->is_unique = ephy_tbi_is_unique_impl; - EPHY_TB_ITEM_CLASS (klass)->clone = ephy_tbi_clone_impl; - EPHY_TB_ITEM_CLASS (klass)->parse_properties = ephy_tbi_parse_properties_impl; - EPHY_TB_ITEM_CLASS (klass)->add_to_bonobo_tb = ephy_tbi_add_to_bonobo_tb_impl; - - ephy_tb_item_class = g_type_class_peek_parent (klass); -} - -static void -ephy_tbi_init (EphyTbi *tbi) -{ - tbi->window = NULL; -} - -static void -ephy_tbi_finalize_impl (GObject *o) -{ - EphyTbi *it = EPHY_TBI (o); - - if (it->window) - { - g_object_remove_weak_pointer (G_OBJECT (it->window), - (gpointer *) &it->window); - } - - LOG ("EphyTbi finalized") - - G_OBJECT_CLASS (ephy_tb_item_class)->finalize (o); -} - -static GtkWidget * -ephy_tbi_get_widget_impl (EphyTbItem *i) -{ - /* this class is abstract */ - g_assert_not_reached (); - - return NULL; -} - -static GdkPixbuf * -ephy_tbi_get_icon_impl (EphyTbItem *i) -{ - return NULL; -} - -static gchar * -ephy_tbi_get_name_human_impl (EphyTbItem *i) -{ - /* this class is abstract */ - g_assert_not_reached (); - - return NULL; -} - -static gchar * -ephy_tbi_to_string_impl (EphyTbItem *i) -{ - /* this class is abstract */ - g_assert_not_reached (); - - return NULL; -} - -static gboolean -ephy_tbi_is_unique_impl (EphyTbItem *i) -{ - return TRUE; -} - -static EphyTbItem * -ephy_tbi_clone_impl (EphyTbItem *i) -{ - /* you can't clone this directly because this class is abstract */ - g_assert_not_reached (); - return NULL; -} - -static void -ephy_tbi_add_to_bonobo_tb_impl (EphyTbItem *i, BonoboUIComponent *ui, - const char *container_path, guint index) -{ - GtkWidget *w = ephy_tb_item_get_widget (i); - gtk_widget_show (w); - ephy_bonobo_add_numbered_widget (ui, w, index, container_path); -} - -static void -ephy_tbi_parse_properties_impl (EphyTbItem *it, const gchar *props) -{ - /* we have no properties */ -} - -void -ephy_tbi_set_window (EphyTbi *it, EphyWindow *w) -{ - if (it->window) - { - g_object_remove_weak_pointer (G_OBJECT (it->window), - (gpointer *) &it->window); - } - - it->window = w; - - if (it->window) - { - g_object_add_weak_pointer (G_OBJECT (it->window), - (gpointer *) &it->window); - } -} - -EphyWindow * -ephy_tbi_get_window (EphyTbi *tbi) -{ - return tbi->window; -} - diff --git a/src/ephy-tbi.h b/src/ephy-tbi.h deleted file mode 100644 index 2296a144f..000000000 --- a/src/ephy-tbi.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2002 Ricardo Fernández Pascual - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef EPHY_TBI_H -#define EPHY_TBI_H - -#include "ephy-toolbar-item.h" -#include "ephy-window.h" - -G_BEGIN_DECLS - -/* object forward declarations */ - -typedef struct _EphyTbi EphyTbi; -typedef struct _EphyTbiClass EphyTbiClass; -typedef struct _EphyTbiPrivate EphyTbiPrivate; - -/** - * Tbi object - */ - -#define EPHY_TYPE_TBI (ephy_tbi_get_type()) -#define EPHY_TBI(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EPHY_TYPE_TBI,\ - EphyTbi)) -#define EPHY_TBI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EPHY_TYPE_TBI,\ - EphyTbiClass)) -#define EPHY_IS_TBI_(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EPHY_TYPE_TBI)) -#define EPHY_IS_TBI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EPHY_TYPE_TBI)) -#define EPHY_TBI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), EPHY_TYPE_TBI,\ - EphyTbiClass)) - -struct _EphyTbiClass -{ - EphyTbItemClass parent_class; - -}; - -/* Remember: fields are public read-only */ -struct _EphyTbi -{ - EphyTbItem parent_object; - - EphyWindow *window; -}; - -/* this class is abstract */ - -GType ephy_tbi_get_type (void); -EphyTbi * ephy_tbi_new (void); -void ephy_tbi_set_window (EphyTbi *tbi, EphyWindow *w); -EphyWindow * ephy_tbi_get_window (EphyTbi *tbi); - -G_END_DECLS - -#endif diff --git a/src/ephy-window.c b/src/ephy-window.c index 455602244..8cca7ba26 100644 --- a/src/ephy-window.c +++ b/src/ephy-window.c @@ -24,123 +24,250 @@ #include "ephy-favorites-menu.h" #include "ephy-state.h" #include "ephy-gobject-misc.h" -#include "statusbar.h" -#include "toolbar.h" #include "ppview-toolbar.h" #include "window-commands.h" #include "find-dialog.h" #include "history-dialog.h" -#include "popup-commands.h" #include "ephy-shell.h" -#include "ephy-bonobo-extensions.h" #include "eel-gconf-extensions.h" #include "ephy-prefs.h" #include "ephy-embed-utils.h" #include "ephy-debug.h" +#include "ephy-file-helpers.h" +#include "statusbar.h" +#include "toolbar.h" +#include "popup-commands.h" #include <string.h> -#include <bonobo/bonobo-window.h> -#include <bonobo/bonobo-i18n.h> -#include <bonobo/bonobo-ui-util.h> -#include <bonobo/bonobo-ui-component.h> +#include <libgnome/gnome-i18n.h> #include <libgnomevfs/gnome-vfs-uri.h> #include <gtk/gtk.h> #include <X11/X.h> #include <X11/Xlib.h> #include <gdk/gdkx.h> #include <gdk/gdkkeysyms.h> +#include "egg-action-group.h" +#include "egg-menu-merge.h" #define CHARSET_MENU_PATH "/menu/View/EncodingMenuPlaceholder" #define GO_FAVORITES_PATH "/menu/Go/Favorites" -#define GO_BACK_CMD_PATH "/commands/GoBack" -#define GO_FORWARD_CMD_PATH "/commands/GoForward" -#define GO_UP_CMD_PATH "/commands/GoUp" -#define EDIT_FIND_NEXT_CMD_PATH "/commands/EditFindNext" -#define EDIT_FIND_PREV_CMD_PATH "/commands/EditFindPrev" -#define VIEW_MENUBAR_PATH "/commands/View Menubar" -#define VIEW_STATUSBAR_PATH "/commands/View Statusbar" -#define VIEW_TOOLBAR_PATH "/commands/View Toolbar" -#define VIEW_BOOKMARKSBAR_PATH "/commands/View BookmarksBar" -#define VIEW_FULLSCREEN_PATH "/commands/View Fullscreen" - -#define ID_VIEW_MENUBAR "View Menubar" -#define ID_VIEW_STATUSBAR "View Statusbar" -#define ID_VIEW_TOOLBAR "View Toolbar" -#define ID_VIEW_BOOKMARKSBAR "View BookmarksBar" -#define ID_VIEW_FULLSCREEN "View Fullscreen" - -static BonoboUIVerb ephy_verbs [] = { - BONOBO_UI_VERB ("EditFind", (BonoboUIVerbFn)window_cmd_edit_find), - BONOBO_UI_VERB ("FilePrint", (BonoboUIVerbFn)window_cmd_file_print), - BONOBO_UI_VERB ("GoStop", (BonoboUIVerbFn)window_cmd_go_stop), - BONOBO_UI_VERB ("GoReload", (BonoboUIVerbFn)window_cmd_go_reload), - BONOBO_UI_VERB ("GoBack", (BonoboUIVerbFn)window_cmd_go_back), - BONOBO_UI_VERB ("GoForward", (BonoboUIVerbFn)window_cmd_go_forward), - BONOBO_UI_VERB ("GoGo", (BonoboUIVerbFn)window_cmd_go_go), - BONOBO_UI_VERB ("GoUp", (BonoboUIVerbFn)window_cmd_go_up), - BONOBO_UI_VERB ("GoHome", (BonoboUIVerbFn)window_cmd_go_home), - BONOBO_UI_VERB ("GoMyportal", (BonoboUIVerbFn)window_cmd_go_myportal), - BONOBO_UI_VERB ("GoLocation", (BonoboUIVerbFn)window_cmd_go_location), - BONOBO_UI_VERB ("FileNew", (BonoboUIVerbFn)window_cmd_new), - BONOBO_UI_VERB ("FileNewWindow", (BonoboUIVerbFn)window_cmd_new_window), - BONOBO_UI_VERB ("FileNewTab", (BonoboUIVerbFn)window_cmd_new_tab), - BONOBO_UI_VERB ("FileOpen", (BonoboUIVerbFn)window_cmd_file_open), - BONOBO_UI_VERB ("FileSaveAs", (BonoboUIVerbFn)window_cmd_file_save_as), - BONOBO_UI_VERB ("FileCloseTab", (BonoboUIVerbFn)window_cmd_file_close_tab), - BONOBO_UI_VERB ("FileCloseWindow", (BonoboUIVerbFn)window_cmd_file_close_window), - BONOBO_UI_VERB ("FileSendTo", (BonoboUIVerbFn)window_cmd_file_send_to), - BONOBO_UI_VERB ("EditCut", (BonoboUIVerbFn)window_cmd_edit_cut), - BONOBO_UI_VERB ("EditCopy", (BonoboUIVerbFn)window_cmd_edit_copy), - BONOBO_UI_VERB ("EditPaste", (BonoboUIVerbFn)window_cmd_edit_paste), - BONOBO_UI_VERB ("EditSelectAll", (BonoboUIVerbFn)window_cmd_edit_select_all), - BONOBO_UI_VERB ("EditPrefs", (BonoboUIVerbFn)window_cmd_edit_prefs), - BONOBO_UI_VERB ("SettingsToolbarEditor", (BonoboUIVerbFn)window_cmd_settings_toolbar_editor), - BONOBO_UI_VERB ("Zoom In", (BonoboUIVerbFn)window_cmd_view_zoom_in), - BONOBO_UI_VERB ("EditFindNext", (BonoboUIVerbFn)window_cmd_edit_find_next), - BONOBO_UI_VERB ("EditFindPrev", (BonoboUIVerbFn)window_cmd_edit_find_prev), - BONOBO_UI_VERB ("Zoom Out", (BonoboUIVerbFn)window_cmd_view_zoom_out), - BONOBO_UI_VERB ("Zoom Normal", (BonoboUIVerbFn)window_cmd_view_zoom_normal), - BONOBO_UI_VERB ("ViewPageSource", (BonoboUIVerbFn)window_cmd_view_page_source), - BONOBO_UI_VERB ("BookmarksAddDefault", (BonoboUIVerbFn)window_cmd_bookmarks_add_default), - BONOBO_UI_VERB ("BookmarksEdit", (BonoboUIVerbFn)window_cmd_bookmarks_edit), - BONOBO_UI_VERB ("ToolsHistory", (BonoboUIVerbFn)window_cmd_tools_history), - BONOBO_UI_VERB ("ToolsPDM", (BonoboUIVerbFn)window_cmd_tools_pdm), - BONOBO_UI_VERB ("TabsNext", (BonoboUIVerbFn)window_cmd_tabs_next), - BONOBO_UI_VERB ("TabsPrevious", (BonoboUIVerbFn)window_cmd_tabs_previous), - BONOBO_UI_VERB ("TabsMoveLeft", (BonoboUIVerbFn)window_cmd_tabs_move_left), - BONOBO_UI_VERB ("TabsMoveRight", (BonoboUIVerbFn)window_cmd_tabs_move_right), - BONOBO_UI_VERB ("TabsDetach", (BonoboUIVerbFn)window_cmd_tabs_detach), - BONOBO_UI_VERB ("HelpContents", (BonoboUIVerbFn)window_cmd_help_manual), - BONOBO_UI_VERB ("About", (BonoboUIVerbFn)window_cmd_help_about), - - BONOBO_UI_VERB_END +#define GO_BACK_ACTION "GoBack" +#define GO_FORWARD_ACTION "GoForward" +#define GO_UP_ACTION "GoUp" +#define EDIT_FIND_NEXT_ACTION "EditFindNext" +#define EDIT_FIND_PREV_ACTION "EditFindPrev" +#define VIEW_STATUSBAR_ACTION "ViewStatusbar" +#define VIEW_TOOLBAR_ACTION "ViewToolbar" +#define VIEW_FULLSCREEN_ACTION "ViewFullscreen" + +static EggActionGroupEntry ephy_menu_entries [] = { + + /* Toplevel */ + { "File", N_("_File"), NULL, NULL, NULL, NULL, NULL }, + { "Edit", N_("_Edit"), NULL, NULL, NULL, NULL, NULL }, + { "View", N_("_View"), NULL, NULL, NULL, NULL, NULL }, + { "Go", N_("_Go"), NULL, NULL, NULL, NULL, NULL }, + { "Tabs", N_("_Tabs"), NULL, NULL, NULL, NULL, NULL }, + { "Help", N_("_Help"), NULL, NULL, NULL, NULL, NULL }, + + /* File menu */ + { "FileNewWindow", N_("_New Window"), GTK_STOCK_NEW, "<control>N", + N_("Create a new window"), + G_CALLBACK (window_cmd_file_new_window), NULL }, + { "FileNewTab", N_("New _Tab"), NULL, "<shift><control>N", + N_("Create a new tab"), + G_CALLBACK (window_cmd_file_new_tab), NULL }, + { "FileOpen", N_("_Open..."), GTK_STOCK_OPEN, "<control>O", + N_("Open a file"), + G_CALLBACK (window_cmd_file_open), NULL }, + { "FileSaveAs", N_("Save _As..."), GTK_STOCK_SAVE, "<shift><control>S", + N_("Save the current page"), + G_CALLBACK (window_cmd_file_save_as), NULL }, + { "FilePrint", N_("_Print..."), GTK_STOCK_PRINT, "<control>P", + N_("Print the current page"), + G_CALLBACK (window_cmd_file_print), NULL }, + { "FileSendTo", N_("S_end To..."), NULL, NULL, + N_("Send a link of the current page"), + G_CALLBACK (window_cmd_file_send_to), NULL }, + { "FileAddBookmark", N_("_Add Bookmark..."), GTK_STOCK_ADD, "<control>D", + N_("Add a bookmark for the current page"), + G_CALLBACK (window_cmd_file_add_bookmark), NULL }, + { "FileCloseTab", N_("_Close Tab"), GTK_STOCK_CLOSE, "<control>W", + N_("Send a link of the current page"), + G_CALLBACK (window_cmd_file_close_tab), NULL }, + { "FileCloseWindow", N_("Close _Window"), NULL, "<shift><control>W", + N_("Send a link of the current page"), + G_CALLBACK (window_cmd_file_close_window), NULL }, + + /* Edit menu */ + { "EditCut", N_("Cu_t"), GTK_STOCK_CUT, "<control>X", + N_("Cut the selection"), + G_CALLBACK (window_cmd_edit_cut), NULL }, + { "EditCopy", N_("_Copy"), GTK_STOCK_COPY, "<control>C", + N_("Copy the selection"), + G_CALLBACK (window_cmd_edit_copy), NULL }, + { "EditPaste", N_("_Paste"), GTK_STOCK_PASTE, "<control>V", + N_("Paste clipboard"), + G_CALLBACK (window_cmd_edit_paste), NULL }, + { "EditSelectAll", N_("Select _All"), NULL, "<control>A", + N_("Select the entire page"), + G_CALLBACK (window_cmd_edit_select_all), NULL }, + { "EditFind", N_("_Find"), GTK_STOCK_FIND, "<control>F", + N_("Find a string"), + G_CALLBACK (window_cmd_edit_find), NULL }, + { "EditFindNext", N_("Find Ne_xt"), NULL, "<control>G", + N_("Find next occurence of the string"), + G_CALLBACK (window_cmd_edit_find_next), NULL }, + { "EditFindPrev", N_("Find Pre_vious"), NULL, "<shift><control>G", + N_("Find previous occurence of the string"), + G_CALLBACK (window_cmd_edit_find_prev), NULL }, + { "EditPersonalData", N_("P_ersonal Data"), NULL, "<control>F", + N_("View and remove cookies and passwords"), + G_CALLBACK (window_cmd_edit_personal_data), NULL }, + { "EditToolbar", N_("T_oolbars"), NULL, NULL, + N_("Costumize toolbars"), + G_CALLBACK (window_cmd_edit_toolbar), NULL }, + { "EditPrefs", N_("P_references"), GTK_STOCK_PREFERENCES, NULL, + N_("Configure the web browser"), + G_CALLBACK (window_cmd_edit_prefs), NULL }, + + /* View menu */ + { "ViewStop", N_("_Stop"), GTK_STOCK_STOP, "Escape", + N_("Stop current data transfer"), + G_CALLBACK (window_cmd_view_stop), NULL }, + { "ViewReload", N_("_Reload"), GTK_STOCK_REFRESH, "<control>R", + N_("Display the latest content of the current page"), + G_CALLBACK (window_cmd_view_reload), NULL }, + { "ViewStatusbar", N_("St_atusbar"), NULL, NULL, + N_("Show or hide statusbar"), + G_CALLBACK (window_cmd_view_statusbar), NULL, TOGGLE_ACTION }, + { "ViewFullscreen", N_("_Fullscreen"), NULL, NULL, + N_("Browse at full screen"), + G_CALLBACK (window_cmd_view_fullscreen), NULL, TOGGLE_ACTION}, + { "ViewZoomIn", N_("Zoom _In"), GTK_STOCK_ZOOM_IN, "<control>plus", + N_("Show the contents in more detail"), + G_CALLBACK (window_cmd_view_zoom_in), NULL }, + { "ViewZoomOut", N_("Zoom _Out"), GTK_STOCK_ZOOM_OUT, "<control>minus", + N_("Show the contents in less detail"), + G_CALLBACK (window_cmd_view_zoom_out), NULL }, + { "ViewZoomNormal", N_("_Normal Size"), GTK_STOCK_ZOOM_100, NULL, + N_("Show the contents at the normal size"), + G_CALLBACK (window_cmd_view_zoom_normal), NULL }, + { "ViewPageSource", N_("_Page Source"), NULL, NULL, + N_("View the source code of the page"), + G_CALLBACK (window_cmd_view_page_source), NULL }, + + /* Go menu */ + { "GoBack", N_("_Back"), GTK_STOCK_GO_BACK, "<alt>left", + N_("Go to the previous visited page"), + G_CALLBACK (window_cmd_go_back), NULL }, + { "GoForward", N_("_Forward"), GTK_STOCK_GO_FORWARD, "<alt>right", + N_("Go to the next visited page"), + G_CALLBACK (window_cmd_go_forward), NULL }, + { "GoUp", N_("_Up"), GTK_STOCK_GO_UP, "<alt>up", + N_("Go up one level"), + G_CALLBACK (window_cmd_go_up), NULL }, + { "GoHome", N_("_Home"), GTK_STOCK_HOME, "<alt>home", + N_("Go to the home page"), + G_CALLBACK (window_cmd_go_home), NULL }, + { "GoLocation", N_("_Location..."), NULL, "<control>L", + N_("Go to a specified location"), + G_CALLBACK (window_cmd_go_location), NULL }, + { "GoHistory", N_("_History"), NULL, "<control>H", + N_("Go to an already visited page"), + G_CALLBACK (window_cmd_go_history), NULL }, + { "GoBookmarks", N_("_Bookmarks"), NULL, "<control>B", + N_("Go to a bookmark"), + G_CALLBACK (window_cmd_go_bookmarks), NULL }, + + /* Tabs menu */ + { "TabsPrevious", N_("_Previous Tab"), NULL, "<control>page_up", + N_("Activate previous tab"), + G_CALLBACK (window_cmd_tabs_previous), NULL }, + { "TabsNext", N_("_Next Tab"), NULL, "<control>page_down", + N_("Activate next tab"), + G_CALLBACK (window_cmd_tabs_next), NULL }, + { "TabsMoveLeft", N_("Move Tab _Left"), NULL, "<shift><control>page_up", + N_("Move current tab to left"), + G_CALLBACK (window_cmd_tabs_move_left), NULL }, + { "TabsMoveRight", N_("Move Tab _Right"), NULL, "<shift><control>page_up", + N_("Move current tab to right"), + G_CALLBACK (window_cmd_tabs_move_right), NULL }, + { "TabsDetach", N_("_Detach Tab"), NULL, "<shift><control>M", + N_("Detach current tab"), + G_CALLBACK (window_cmd_tabs_detach), NULL }, + + /* Help menu */ + { "HelpAbout", N_("_About"), NULL, NULL, + N_("Display credits for the web browser creators"), + G_CALLBACK (window_cmd_help_about), NULL }, }; - -static BonoboUIVerb ephy_popup_verbs [] = { - BONOBO_UI_VERB ("EPOpenInNewWindow", (BonoboUIVerbFn)popup_cmd_new_window), - BONOBO_UI_VERB ("EPOpenInNewTab", (BonoboUIVerbFn)popup_cmd_new_tab), - BONOBO_UI_VERB ("EPAddBookmark", (BonoboUIVerbFn)popup_cmd_add_bookmark), - BONOBO_UI_VERB ("EPOpenImageInNewWindow", (BonoboUIVerbFn)popup_cmd_image_in_new_window), - BONOBO_UI_VERB ("EPOpenImageInNewTab", (BonoboUIVerbFn)popup_cmd_image_in_new_tab), - BONOBO_UI_VERB ("DPOpenFrameInNewWindow", (BonoboUIVerbFn)popup_cmd_frame_in_new_window), - BONOBO_UI_VERB ("DPOpenFrameInNewTab", (BonoboUIVerbFn)popup_cmd_frame_in_new_tab), - BONOBO_UI_VERB ("DPAddFrameBookmark", (BonoboUIVerbFn)popup_cmd_add_frame_bookmark), - BONOBO_UI_VERB ("DPViewSource", (BonoboUIVerbFn)popup_cmd_view_source), - - BONOBO_UI_VERB_END +static guint ephy_menu_n_entries = G_N_ELEMENTS (ephy_menu_entries); + +static EggActionGroupEntry ephy_popups_entries [] = { + /* Toplevel */ + { "FakeToplevel", (""), NULL, NULL, NULL, NULL, NULL }, + + /* Document */ + { "SaveBackgroundAs", N_("Save Background As..."), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_save_background_as), NULL }, + { "CopyPageLocation", N_("Copy Page Location"), GTK_STOCK_COPY, NULL, + NULL, G_CALLBACK (popup_cmd_copy_page_location), NULL }, + + /* Framed document */ + { "OpenFrame", N_("Open Frame"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_open_frame), NULL }, + { "OpenFrameInNewWindow", N_("Open Frame in New Window"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_frame_in_new_window), NULL }, + { "OpenFrameInNewTab", N_("Open Frame in New Tab"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_frame_in_new_tab), NULL }, + + /* Links */ + { "OpenLink", N_("Open Link"), GTK_STOCK_OPEN, NULL, + NULL, G_CALLBACK (popup_cmd_open_link), NULL }, + { "OpenLinkInNewWindow", N_("Open Link in New Window"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_link_in_new_window), NULL }, + { "OpenLinkInNewTab", N_("Open Link in New Tab"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_link_in_new_tab), NULL }, + { "DownloadLink", N_("Download Link"), GTK_STOCK_SAVE, NULL, + NULL, G_CALLBACK (popup_cmd_download_link), NULL }, + { "AddLinkBookmark", N_("Add Bookmark"), GTK_STOCK_ADD, NULL, + NULL, G_CALLBACK (popup_cmd_add_link_bookmark), NULL }, + { "CopyLinkLocation", N_("Copy Link Location"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_copy_link_location), NULL }, + { "CopyEmail", N_("Copy Email"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_copy_email), NULL }, + + /* Images */ + { "OpenImage", N_("Open Image"), GTK_STOCK_OPEN, NULL, + NULL, G_CALLBACK (popup_cmd_open_image), NULL }, + { "OpenImageInNewWindow", N_("Open Image in New Window"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_image_in_new_window), NULL }, + { "OpenImageInNewTab", N_("Open Image in New Tab"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_image_in_new_tab), NULL }, + { "SaveImageAs", N_("Save Image As..."), GTK_STOCK_SAVE_AS, NULL, + NULL, G_CALLBACK (popup_cmd_save_image_as), NULL }, + { "SetImageAsBackground", N_("Use Image as Background"), NULL, NULL, + NULL, G_CALLBACK (popup_cmd_set_image_as_background), NULL }, + { "CopyImageLocation", N_("Copy Image Location"), GTK_STOCK_COPY, NULL, + NULL, G_CALLBACK (popup_cmd_copy_image_location), NULL }, }; +static guint ephy_popups_n_entries = G_N_ELEMENTS (ephy_popups_entries); struct EphyWindowPrivate { + GtkWidget *main_vbox; + GtkWidget *menubar; + Toolbar *toolbar; + GtkWidget *statusbar; + EggActionGroup *action_group; + EggActionGroup *popups_action_group; EphyFavoritesMenu *fav_menu; PPViewToolbar *ppview_toolbar; - Toolbar *toolbar; - Statusbar *statusbar; GtkNotebook *notebook; EphyTab *active_tab; GtkWidget *sidebar; - EphyEmbedPopupBW *embed_popup; EphyDialog *find_dialog; EphyDialog *history_dialog; EphyDialog *history_sidebar; @@ -191,7 +318,7 @@ ephy_window_get_type (void) (GInstanceInitFunc) ephy_window_init }; - ephy_window_type = g_type_register_static (BONOBO_TYPE_WINDOW, + ephy_window_type = g_type_register_static (GTK_TYPE_WINDOW, "EphyWindow", &our_info, 0); } @@ -212,8 +339,7 @@ ephy_window_class_init (EphyWindowClass *klass) widget_class->show = ephy_window_show; } -static -gboolean +static gboolean ephy_window_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, EphyWindow *window) @@ -287,63 +413,75 @@ ephy_window_state_event_cb (GtkWidget *widget, } static void -setup_bonobo_window (EphyWindow *window, - BonoboUIComponent **ui_component) +add_widget (EggMenuMerge *merge, GtkWidget *widget, EphyWindow *window) +{ + if (GTK_IS_MENU_SHELL (widget)) + { + window->priv->menubar = widget; + } + + gtk_box_pack_start (GTK_BOX (window->priv->main_vbox), + widget, FALSE, FALSE, 0); + gtk_widget_show (widget); +} + +static void +setup_window (EphyWindow *window) { - BonoboWindow *win = BONOBO_WINDOW(window); - BonoboUIContainer *container; - Bonobo_UIContainer corba_container; + EggActionGroup *action_group; + EggMenuMerge *merge; + int i; + + window->priv->main_vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (window->priv->main_vbox); + gtk_container_add (GTK_CONTAINER (window), + window->priv->main_vbox); + + for (i = 0; i < ephy_menu_n_entries; i++) + { + ephy_menu_entries[i].user_data = window; + } - container = bonobo_window_get_ui_container (win); + for (i = 0; i < ephy_popups_n_entries; i++) + { + ephy_popups_entries[i].user_data = window; + } - bonobo_ui_engine_config_set_path (bonobo_window_get_ui_engine (win), - "/apps/ephy/UIConfig/kvps"); + merge = egg_menu_merge_new (); - corba_container = BONOBO_OBJREF (container); + action_group = egg_action_group_new ("WindowActions"); + egg_action_group_add_actions (action_group, ephy_menu_entries, + ephy_menu_n_entries); + egg_menu_merge_insert_action_group (merge, action_group, 0); + window->priv->action_group = action_group; - *ui_component = bonobo_ui_component_new_default (); + action_group = egg_action_group_new ("PopupsActions"); + egg_action_group_add_actions (action_group, ephy_popups_entries, + ephy_popups_n_entries); + egg_menu_merge_insert_action_group (merge, action_group, 0); + window->priv->popups_action_group = action_group; - bonobo_ui_component_set_container (*ui_component, - corba_container, - NULL); + window->ui_merge = G_OBJECT (merge); + g_signal_connect (merge, "add_widget", G_CALLBACK (add_widget), window); + egg_menu_merge_add_ui_from_file (merge, ephy_file ("epiphany-ui.xml"), NULL); + gtk_window_add_accel_group (GTK_WINDOW (window), merge->accel_group); - bonobo_ui_util_set_ui (*ui_component, - DATADIR, - "epiphany-ui.xml", - "ephy", NULL); + window->priv->toolbar = toolbar_new (window); - /* Key handling */ - g_signal_connect(G_OBJECT(win), + g_signal_connect(window, "key-press-event", G_CALLBACK(ephy_window_key_press_event_cb), window); - - g_signal_connect (G_OBJECT(win), "configure_event", + g_signal_connect (window, "configure_event", G_CALLBACK (ephy_window_configure_event_cb), NULL); - g_signal_connect (G_OBJECT(win), "window_state_event", + g_signal_connect (window, "window_state_event", G_CALLBACK (ephy_window_state_event_cb), NULL); - - g_signal_connect (G_OBJECT(win), + g_signal_connect (window, "selection-received", G_CALLBACK (ephy_window_selection_received_cb), window); } -static EphyEmbedPopupBW * -setup_popup_factory (EphyWindow *window, - BonoboUIComponent *ui_component) -{ - EphyEmbedPopupBW *popup; - - popup = ephy_window_get_popup_factory (window); - g_object_set_data (G_OBJECT(popup), "EphyWindow", window); - bonobo_ui_component_add_verb_list_with_data (ui_component, - ephy_popup_verbs, - popup); - - return popup; -} - static GtkNotebook * setup_notebook (EphyWindow *window) { @@ -369,89 +507,6 @@ setup_notebook (EphyWindow *window) } static void -view_toolbar_changed_cb (BonoboUIComponent *component, - const char *path, - Bonobo_UIComponent_EventType type, - const char *state, - EphyWindow *window) -{ - EmbedChromeMask mask; - - if (window->priv->ignore_layout_toggles) return; - - mask = ephy_window_get_chrome (window); - mask ^= EMBED_CHROME_TOOLBARON; - ephy_window_set_chrome (window, mask); -} - -static void -view_statusbar_changed_cb (BonoboUIComponent *component, - const char *path, - Bonobo_UIComponent_EventType type, - const char *state, - EphyWindow *window) -{ - EmbedChromeMask mask; - - if (window->priv->ignore_layout_toggles) return; - - mask = ephy_window_get_chrome (window); - mask ^= EMBED_CHROME_STATUSBARON; - ephy_window_set_chrome (window, mask); -} - -static void -view_fullscreen_changed_cb (BonoboUIComponent *component, - const char *path, - Bonobo_UIComponent_EventType type, - const char *state, - EphyWindow *window) -{ - EmbedChromeMask mask; - - if (window->priv->ignore_layout_toggles) return; - - mask = ephy_window_get_chrome (window); - mask ^= EMBED_CHROME_OPENASFULLSCREEN; - mask |= EMBED_CHROME_DEFAULT; - ephy_window_set_chrome (window, mask); -} - -static void -update_layout_toggles (EphyWindow *window) -{ - BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component); - EmbedChromeMask mask = window->priv->chrome_mask; - - window->priv->ignore_layout_toggles = TRUE; - - ephy_bonobo_set_toggle_state (ui_component, VIEW_TOOLBAR_PATH, - mask & EMBED_CHROME_TOOLBARON); - ephy_bonobo_set_toggle_state (ui_component, VIEW_STATUSBAR_PATH, - mask & EMBED_CHROME_STATUSBARON); - ephy_bonobo_set_toggle_state (ui_component, VIEW_FULLSCREEN_PATH, - mask & EMBED_CHROME_OPENASFULLSCREEN); - - window->priv->ignore_layout_toggles = FALSE; -} - -static void -setup_layout_menus (EphyWindow *window) -{ - BonoboUIComponent *ui_component = BONOBO_UI_COMPONENT (window->ui_component); - - bonobo_ui_component_add_listener (ui_component, ID_VIEW_TOOLBAR, - (BonoboUIListenerFn)view_toolbar_changed_cb, - window); - bonobo_ui_component_add_listener (ui_component, ID_VIEW_STATUSBAR, - (BonoboUIListenerFn)view_statusbar_changed_cb, - window); - bonobo_ui_component_add_listener (ui_component, ID_VIEW_FULLSCREEN, - (BonoboUIListenerFn)view_fullscreen_changed_cb, - window); -} - -static void favicon_cache_changed_cb (EphyFaviconCache *cache, char *url, EphyWindow *window) { ephy_window_update_control (window, FaviconControl); @@ -460,14 +515,12 @@ favicon_cache_changed_cb (EphyFaviconCache *cache, char *url, EphyWindow *window static void ephy_window_init (EphyWindow *window) { - BonoboUIComponent *ui_component; Session *session; EphyFaviconCache *cache; session = ephy_shell_get_session (ephy_shell); window->priv = g_new0 (EphyWindowPrivate, 1); - window->priv->embed_popup = NULL; window->priv->active_tab = NULL; window->priv->chrome_mask = 0; window->priv->ignore_layout_toggles = FALSE; @@ -482,42 +535,25 @@ ephy_window_init (EphyWindow *window) 0); /* Setup the window and connect verbs */ - setup_bonobo_window (window, &ui_component); - window->ui_component = G_OBJECT (ui_component); - bonobo_ui_component_add_verb_list_with_data (ui_component, - ephy_verbs, - window); - setup_layout_menus (window); - - /* Setup the embed popups factory */ - window->priv->embed_popup = setup_popup_factory (window, - ui_component); - - bonobo_ui_component_freeze (ui_component, NULL); - - /* Setup menubar */ - ephy_embed_utils_build_charsets_submenu (ui_component, - CHARSET_MENU_PATH, - (BonoboUIVerbFn)window_cmd_set_charset, - window); - window->priv->fav_menu = ephy_favorites_menu_new (window); - ephy_favorites_menu_set_path (window->priv->fav_menu, GO_FAVORITES_PATH); + setup_window (window); - /* Setup toolbar and statusbar */ - window->priv->toolbar = toolbar_new (window); - window->priv->statusbar = statusbar_new (window); - window->priv->ppview_toolbar = ppview_toolbar_new (window); + window->priv->fav_menu = ephy_favorites_menu_new (window); /* Setup window contents */ window->priv->notebook = setup_notebook (window); - bonobo_window_set_contents (BONOBO_WINDOW (window), - GTK_WIDGET (window->priv->notebook)); + gtk_box_pack_start (GTK_BOX (window->priv->main_vbox), + GTK_WIDGET (window->priv->notebook), + TRUE, TRUE, 0); - bonobo_ui_component_thaw (ui_component, NULL); + window->priv->statusbar = statusbar_new (); + gtk_widget_show (window->priv->statusbar); + gtk_box_pack_start (GTK_BOX (window->priv->main_vbox), + GTK_WIDGET (window->priv->statusbar), + FALSE, TRUE, 0); g_object_ref (ephy_shell); - /*Once window is fully created, add it to the session list*/ + /* Once window is fully created, add it to the session list*/ session_add_window (session, window); } @@ -572,14 +608,6 @@ ephy_window_finalize (GObject *object) remove_from_session (window); - if (window->priv->embed_popup) - { - g_object_unref (G_OBJECT (window->priv->embed_popup)); - } - - g_object_unref (G_OBJECT (window->priv->toolbar)); - g_object_unref (G_OBJECT (window->priv->statusbar)); - if (window->priv->find_dialog) { g_object_unref (G_OBJECT (window->priv->find_dialog)); @@ -592,7 +620,14 @@ ephy_window_finalize (GObject *object) (gpointer *)&window->priv->history_dialog); } - g_free (window->priv); + g_object_unref (window->priv->fav_menu); + + if (window->priv->ppview_toolbar) + { + g_object_unref (window->priv->ppview_toolbar); + } + + g_free (window->priv); G_OBJECT_CLASS (parent_class)->finalize (object); @@ -607,16 +642,6 @@ ephy_window_new (void) return EPHY_WINDOW (g_object_new (EPHY_WINDOW_TYPE, NULL)); } -static void -dock_item_set_visibility (EphyWindow *window, - const char *path, - gboolean visibility) -{ - ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(window->ui_component), - path, - !visibility); -} - EmbedChromeMask ephy_window_get_chrome (EphyWindow *window) { @@ -718,29 +743,46 @@ void ephy_window_set_chrome (EphyWindow *window, EmbedChromeMask flags) { - gboolean toolbar, ppvtoolbar, statusbar; - if (flags & EMBED_CHROME_DEFAULT) { translate_default_chrome (&flags); } - dock_item_set_visibility (window, "/menu", - flags & EMBED_CHROME_MENUBARON); + if (flags & EMBED_CHROME_MENUBARON) + { + gtk_widget_show (window->priv->menubar); + } + else + { + gtk_widget_hide (window->priv->menubar); + } - toolbar = (flags & EMBED_CHROME_TOOLBARON) != FALSE; toolbar_set_visibility (window->priv->toolbar, - toolbar); + flags & EMBED_CHROME_TOOLBARON); - statusbar = (flags & EMBED_CHROME_STATUSBARON) != FALSE; - statusbar_set_visibility (window->priv->statusbar, - statusbar); + if (flags & EMBED_CHROME_STATUSBARON) + { + gtk_widget_show (window->priv->statusbar); + } + else + { + gtk_widget_hide (window->priv->statusbar); + } - ppvtoolbar = (flags & EMBED_CHROME_PPVIEWTOOLBARON) != FALSE; - ppview_toolbar_set_old_chrome (window->priv->ppview_toolbar, - window->priv->chrome_mask); - ppview_toolbar_set_visibility (window->priv->ppview_toolbar, - ppvtoolbar); + if ((flags & EMBED_CHROME_PPVIEWTOOLBARON) != FALSE) + { + if (!window->priv->ppview_toolbar) + { + window->priv->ppview_toolbar = ppview_toolbar_new (window); + } + } + else + { + if (window->priv->ppview_toolbar) + { + g_object_unref (window->priv->ppview_toolbar); + } + } /* set fullscreen only when it's really changed */ if ((window->priv->chrome_mask & EMBED_CHROME_OPENASFULLSCREEN) != @@ -753,8 +795,6 @@ ephy_window_set_chrome (EphyWindow *window, window->priv->chrome_mask = flags; - update_layout_toggles (window); - save_window_chrome (window); } @@ -988,14 +1028,11 @@ update_security (EphyWindow *window) static void update_nav_control (EphyWindow *window) { - /* the zoom control is updated at the same time than the navigation - controls. This keeps it synched most of the time, but not always, - because we don't get a notification when zoom changes */ - gresult back, forward, up, stop; EphyEmbed *embed; EphyTab *tab; - gint zoom; + EggActionGroup *action_group; + EggAction *action; g_return_if_fail (window != NULL); @@ -1010,29 +1047,16 @@ update_nav_control (EphyWindow *window) up = ephy_embed_can_go_up (embed); stop = ephy_tab_get_load_status (tab) & TAB_LOAD_STARTED; - toolbar_button_set_sensitive (window->priv->toolbar, - TOOLBAR_BACK_BUTTON, - back == G_OK ? TRUE : FALSE); - toolbar_button_set_sensitive (window->priv->toolbar, - TOOLBAR_FORWARD_BUTTON, - forward == G_OK ? TRUE : FALSE); - toolbar_button_set_sensitive (window->priv->toolbar, - TOOLBAR_UP_BUTTON, - up == G_OK ? TRUE : FALSE); - toolbar_button_set_sensitive (window->priv->toolbar, - TOOLBAR_STOP_BUTTON, - stop); - if (ephy_embed_zoom_get (embed, &zoom) == G_OK) - { - toolbar_set_zoom (window->priv->toolbar, zoom); - } + action_group = window->priv->action_group; + action = egg_action_group_get_action (action_group, "GoBack"); + g_object_set (action, "sensitive", !back, NULL); + action = egg_action_group_get_action (action_group, "GoForward"); + g_object_set (action, "sensitive", !forward, NULL); + action = egg_action_group_get_action (action_group, "GoUp"); + g_object_set (action, "sensitive", !up, NULL); - ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), - GO_BACK_CMD_PATH, !back); - ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), - GO_FORWARD_CMD_PATH, !forward); - ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), - GO_UP_CMD_PATH, !up); + toolbar_update_navigation_actions (window->priv->toolbar, + back, forward, up); } static void @@ -1066,8 +1090,7 @@ update_location_control (EphyWindow *window) if (!location) location = ""; - toolbar_set_location (window->priv->toolbar, - location); + toolbar_set_location (window->priv->toolbar, location); } static void @@ -1108,11 +1131,11 @@ update_find_control (EphyWindow *window) (FIND_DIALOG(window->priv->find_dialog)); can_go_prev = find_dialog_can_go_prev (FIND_DIALOG(window->priv->find_dialog)); - +/* ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), EDIT_FIND_NEXT_CMD_PATH, can_go_next); ephy_bonobo_set_sensitive (BONOBO_UI_COMPONENT(window->ui_component), - EDIT_FIND_PREV_CMD_PATH, can_go_prev); + EDIT_FIND_PREV_CMD_PATH, can_go_prev);*/ } } @@ -1218,7 +1241,7 @@ void ephy_window_update_all_controls (EphyWindow *window) { g_return_if_fail (IS_EPHY_WINDOW (window)); - + if (ephy_window_get_active_tab (window) != NULL) { update_nav_control (window); @@ -1257,21 +1280,6 @@ ephy_window_get_active_embed (EphyWindow *window) else return NULL; } -EphyEmbedPopupBW * -ephy_window_get_popup_factory (EphyWindow *window) -{ - if (!window->priv->embed_popup) - { - window->priv->embed_popup = ephy_embed_popup_bw_new - (BONOBO_WINDOW(window)); - ephy_embed_popup_connect_verbs - (EPHY_EMBED_POPUP (window->priv->embed_popup), - BONOBO_UI_COMPONENT (window->ui_component)); - } - - return window->priv->embed_popup; -} - GList * ephy_window_get_tabs (EphyWindow *window) { @@ -1296,8 +1304,11 @@ ephy_window_get_tabs (EphyWindow *window) static void save_old_embed_status (EphyTab *tab, EphyWindow *window) { - /* save old tab location status */ - ephy_tab_set_location (tab, toolbar_get_location (window->priv->toolbar)); + char *location; + + location = toolbar_get_location (window->priv->toolbar); + ephy_tab_set_location (tab, location); + g_free (location); } static void @@ -1335,9 +1346,9 @@ update_embed_dialogs (EphyWindow *window, static void ephy_window_notebook_switch_page_cb (GtkNotebook *notebook, - GtkNotebookPage *page, - guint page_num, - EphyWindow *window) + GtkNotebookPage *page, + guint page_num, + EphyWindow *window) { EphyTab *tab, *old_tab; diff --git a/src/ephy-window.h b/src/ephy-window.h index 315cd8cca..10712e3ff 100644 --- a/src/ephy-window.h +++ b/src/ephy-window.h @@ -20,13 +20,11 @@ #define EPHY_WINDOW_H #include "ephy-embed.h" -#include "ephy-embed-persist.h" -#include "ephy-embed-popup-bw.h" #include "ephy-dialog.h" #include "ephy-notebook.h" #include <glib-object.h> #include <glib.h> -#include <bonobo/bonobo-window.h> +#include <gtk/gtkwindow.h> G_BEGIN_DECLS @@ -44,16 +42,16 @@ typedef struct Toolbar Toolbar; struct EphyWindow { - BonoboWindow parent; + GtkWindow parent; EphyWindowPrivate *priv; /* Public to toolbar and statusbar, dont use outside */ - GObject *ui_component; + GObject *ui_merge; }; struct EphyWindowClass { - BonoboWindowClass parent_class; + GtkWindowClass parent_class; }; typedef enum @@ -123,8 +121,6 @@ EphyTab *ephy_window_get_active_tab (EphyWindow *window); EphyEmbed *ephy_window_get_active_embed (EphyWindow *window); -EphyEmbedPopupBW *ephy_window_get_popup_factory (EphyWindow *window); - GList *ephy_window_get_tabs (EphyWindow *window); Toolbar *ephy_window_get_toolbar (EphyWindow *window); diff --git a/src/popup-commands.c b/src/popup-commands.c index f1ec8ae74..84ce259c8 100644 --- a/src/popup-commands.c +++ b/src/popup-commands.c @@ -18,47 +18,60 @@ #include "popup-commands.h" #include "ephy-shell.h" +#include "ephy-new-bookmark.h" +#include "ephy-embed-persist.h" +#include "ephy-prefs.h" +#include "ephy-embed-utils.h" +#include "eel-gconf-extensions.h" +#include "ephy-file-helpers.h" -static EphyWindow * -get_window_from_popup (EphyEmbedPopup *popup) +#include <string.h> + +static EphyEmbedEvent * +get_event_info (EphyWindow *window) { - return EPHY_WINDOW (g_object_get_data(G_OBJECT(popup), "EphyWindow")); + EphyEmbedEvent *info; + EphyTab *tab; + + tab = ephy_window_get_active_tab (window); + g_return_val_if_fail (tab != NULL, NULL); + + info = ephy_tab_get_event (tab); + g_return_val_if_fail (info != NULL, NULL); + + return info; } -void popup_cmd_new_window (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_link_in_new_window (EggAction *action, + EphyWindow *window) { EphyEmbedEvent *info; EphyTab *tab; const GValue *value; - tab = ephy_window_get_active_tab (get_window_from_popup (popup)); + tab = ephy_window_get_active_tab (window); - info = ephy_embed_popup_get_event (popup); + info = get_event_info (window); ephy_embed_event_get_property (info, "link", &value); ephy_shell_new_tab (ephy_shell, NULL, tab, - g_value_get_string (value), - EPHY_NEW_TAB_IN_NEW_WINDOW); + g_value_get_string (value), + EPHY_NEW_TAB_IN_NEW_WINDOW); } -void popup_cmd_new_tab (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_link_in_new_tab (EggAction *action, + EphyWindow *window) { EphyEmbedEvent *info; EphyTab *tab; - EphyWindow *window; const GValue *value; - window = get_window_from_popup (popup); - g_return_if_fail (window != NULL); - tab = ephy_window_get_active_tab (window); - info = ephy_embed_popup_get_event (popup); + info = get_event_info (window); ephy_embed_event_get_property (info, "link", &value); @@ -67,21 +80,17 @@ void popup_cmd_new_tab (BonoboUIComponent *uic, EPHY_NEW_TAB_IN_EXISTING_WINDOW); } -void popup_cmd_image_in_new_tab (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_image_in_new_tab (EggAction *action, + EphyWindow *window) { EphyEmbedEvent *info; EphyTab *tab; - EphyWindow *window; const GValue *value; - window = get_window_from_popup (popup); - g_return_if_fail (window != NULL); - tab = ephy_window_get_active_tab (window); - info = ephy_embed_popup_get_event (popup); + info = get_event_info (window); ephy_embed_event_get_property (info, "image", &value); @@ -90,17 +99,17 @@ void popup_cmd_image_in_new_tab (BonoboUIComponent *uic, EPHY_NEW_TAB_IN_EXISTING_WINDOW); } -void popup_cmd_image_in_new_window (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_image_in_new_window (EggAction *action, + EphyWindow *window) { EphyEmbedEvent *info; EphyTab *tab; const GValue *value; - tab = ephy_window_get_active_tab (get_window_from_popup (popup)); + tab = ephy_window_get_active_tab (window); - info = ephy_embed_popup_get_event (popup); + info = get_event_info (window); ephy_embed_event_get_property (info, "image", &value); @@ -109,15 +118,14 @@ void popup_cmd_image_in_new_window (BonoboUIComponent *uic, EPHY_NEW_TAB_IN_NEW_WINDOW); } -void popup_cmd_add_bookmark (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_add_link_bookmark (EggAction *action, + EphyWindow *window) { GtkWidget *new_bookmark; EphyBookmarks *bookmarks; - EphyEmbedEvent *info = ephy_embed_popup_get_event (popup); + EphyEmbedEvent *info; EphyEmbed *embed; - GtkWidget *window; const GValue *link_title; const GValue *link_rel; const GValue *link; @@ -127,8 +135,8 @@ void popup_cmd_add_bookmark (BonoboUIComponent *uic, const char *rel; gboolean is_smart; - embed = ephy_embed_popup_get_embed (popup); - window = gtk_widget_get_toplevel (GTK_WIDGET (embed)); + info = get_event_info (window); + embed = ephy_window_get_active_embed (window); ephy_embed_event_get_property (info, "link_is_smart", &link_is_smart); ephy_embed_event_get_property (info, "link", &link); @@ -157,18 +165,14 @@ void popup_cmd_add_bookmark (BonoboUIComponent *uic, gtk_widget_show (new_bookmark); } -void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_frame_in_new_tab (EggAction *action, + EphyWindow *window) { EphyTab *tab; - EphyWindow *window; EphyEmbed *embed; char *location; - window = get_window_from_popup (popup); - g_return_if_fail (window != NULL); - tab = ephy_window_get_active_tab (window); embed = ephy_window_get_active_embed (window); @@ -182,18 +186,14 @@ void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic, g_free (location); } -void popup_cmd_frame_in_new_window (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_frame_in_new_window (EggAction *action, + EphyWindow *window) { EphyTab *tab; EphyEmbed *embed; - EphyWindow *window; char *location; - window = get_window_from_popup (popup); - g_return_if_fail (window != NULL); - tab = ephy_window_get_active_tab (window); embed = ephy_window_get_active_embed (window); @@ -207,16 +207,260 @@ void popup_cmd_frame_in_new_window (BonoboUIComponent *uic, g_free (location); } -void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +static void +popup_cmd_copy_to_clipboard (EphyWindow *window, const char *text) +{ + gtk_clipboard_set_text (gtk_clipboard_get (GDK_NONE), + text, -1); + gtk_clipboard_set_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY), + text, -1); +} + +void +popup_cmd_copy_page_location (EggAction *action, + EphyWindow *window) +{ + char *location; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_get_location (embed, FALSE, &location); + popup_cmd_copy_to_clipboard (window, location); + g_free (location); +} + +void +popup_cmd_copy_email (EggAction *action, + EphyWindow *window) +{ + EphyEmbedEvent *info; + const char *location; + const GValue *value; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + info = get_event_info (window); + ephy_embed_event_get_property (info, "email", &value); + location = g_value_get_string (value); + popup_cmd_copy_to_clipboard (window, location); +} + +void +popup_cmd_copy_link_location (EggAction *action, + EphyWindow *window) +{ + EphyEmbedEvent *info; + const char *location; + const GValue *value; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + info = get_event_info (window); + ephy_embed_event_get_property (info, "link", &value); + location = g_value_get_string (value); + popup_cmd_copy_to_clipboard (window, location); +} + +static void +save_property_url (EggAction *action, + EphyWindow *window, + gboolean ask_dest, + gboolean show_progress, + const char *property) +{ + EphyEmbedEvent *info; + const char *location; + const GValue *value; + GtkWidget *widget; + EphyEmbedPersist *persist; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + info = get_event_info (window); + ephy_embed_event_get_property (info, property, &value); + location = g_value_get_string (value); + + widget = GTK_WIDGET (embed); + + persist = ephy_embed_persist_new (embed); + + ephy_embed_persist_set_source (persist, location); + + if (show_progress) + { + ephy_embed_persist_set_flags (persist, + EMBED_PERSIST_SHOW_PROGRESS); + } + + ephy_embed_utils_save (GTK_WIDGET (window), + CONF_STATE_DOWNLOADING_DIR, + ask_dest, + FALSE, + persist); +} + +void +popup_cmd_open_link (EggAction *action, + EphyWindow *window) +{ + EphyEmbedEvent *info; + const char *location; + const GValue *value; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + info = get_event_info (window); + ephy_embed_event_get_property (info, "link", &value); + location = g_value_get_string (value); + + ephy_embed_load_url (embed, location); +} + +void +popup_cmd_download_link (EggAction *action, + EphyWindow *window) +{ + save_property_url (action, window, + eel_gconf_get_boolean + (CONF_STATE_DOWNLOADING_DIR), + TRUE, "link"); +} + +void +popup_cmd_save_image_as (EggAction *action, + EphyWindow *window) +{ + save_property_url (action, window, TRUE, FALSE, "image"); +} + +#define CONF_DESKTOP_BG_PICTURE "/desktop/gnome/background/picture_filename" +#define CONF_DESKTOP_BG_TYPE "/desktop/gnome/background/picture_options" + +static void +background_download_completed (EphyEmbedPersist *persist, + gpointer data) +{ + const char *bg; + char *type; + + ephy_embed_persist_get_dest (persist, &bg); + eel_gconf_set_string (CONF_DESKTOP_BG_PICTURE, bg); + + type = eel_gconf_get_string (CONF_DESKTOP_BG_TYPE); + if (type || strcmp (type, "none") == 0) + { + eel_gconf_set_string (CONF_DESKTOP_BG_TYPE, + "wallpaper"); + } + + g_free (type); + + g_object_unref (persist); +} + +void +popup_cmd_set_image_as_background (EggAction *action, + EphyWindow *window) +{ + EphyEmbedEvent *info; + const char *location; + char *dest, *base; + const GValue *value; + EphyEmbedPersist *persist; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + info = get_event_info (window); + ephy_embed_event_get_property (info, "image", &value); + location = g_value_get_string (value); + + persist = ephy_embed_persist_new (embed); + + base = g_path_get_basename (location); + dest = g_build_filename (ephy_dot_dir (), + base, NULL); + + ephy_embed_persist_set_source (persist, location); + ephy_embed_persist_set_dest (persist, dest); + + ephy_embed_persist_save (persist); + + g_signal_connect (persist, "completed", + G_CALLBACK (background_download_completed), + NULL); + + g_free (dest); + g_free (base); +} + +void +popup_cmd_copy_image_location (EggAction *action, + EphyWindow *window) +{ + EphyEmbedEvent *info; + const char *location; + const GValue *value; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + info = get_event_info (window); + ephy_embed_event_get_property (info, "image", &value); + location = g_value_get_string (value); + popup_cmd_copy_to_clipboard (window, location); +} + +void +popup_cmd_save_background_as (EggAction *action, + EphyWindow *window) +{ + save_property_url (action, window, TRUE, FALSE, "background_image"); +} + +void +popup_cmd_open_frame (EggAction *action, + EphyWindow *window) { - /* FIXME implement */ + char *location; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + ephy_embed_get_location (embed, FALSE, &location); + + ephy_embed_load_url (embed, location); } -void popup_cmd_view_source (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname) +void +popup_cmd_open_image (EggAction *action, + EphyWindow *window) { - /* FIXME implement */ + EphyEmbedEvent *info; + const char *location; + const GValue *value; + EphyEmbed *embed; + + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); + + info = get_event_info (window); + ephy_embed_event_get_property (info, "image", &value); + location = g_value_get_string (value); + + ephy_embed_load_url (embed, location); } + diff --git a/src/popup-commands.h b/src/popup-commands.h index e5b369c76..c2ac4fb36 100644 --- a/src/popup-commands.h +++ b/src/popup-commands.h @@ -16,43 +16,69 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "ephy-embed-popup.h" -#include "ephy-new-bookmark.h" +#include "egg-action.h" +#include "ephy-window.h" -#include <bonobo/bonobo-ui-component.h> +void popup_cmd_link_in_new_window (EggAction *action, + EphyWindow *window); -void popup_cmd_new_window (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_link_in_new_tab (EggAction *action, + EphyWindow *window); -void popup_cmd_new_tab (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_image_in_new_tab (EggAction *action, + EphyWindow *window); -void popup_cmd_image_in_new_tab (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_image_in_new_window (EggAction *action, + EphyWindow *window); -void popup_cmd_image_in_new_window (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_add_link_bookmark (EggAction *action, + EphyWindow *window); -void popup_cmd_add_bookmark (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_frame_in_new_tab (EggAction *action, + EphyWindow *window); -void popup_cmd_frame_in_new_tab (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_frame_in_new_window (EggAction *action, + EphyWindow *window); -void popup_cmd_frame_in_new_window (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_add_frame_bookmark (EggAction *action, + EphyWindow *window); -void popup_cmd_add_frame_bookmark (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); +void popup_cmd_view_source (EggAction *action, + EphyWindow *window); + +void popup_cmd_copy_page_location (EggAction *action, + EphyWindow *window); + +void popup_cmd_copy_email (EggAction *action, + EphyWindow *window); + +void popup_cmd_copy_link_location (EggAction *action, + EphyWindow *window); + +void popup_cmd_open_link (EggAction *action, + EphyWindow *window); + +void popup_cmd_download_link (EggAction *action, + EphyWindow *window); + +void popup_cmd_set_image_as_background (EggAction *action, + EphyWindow *window); + +void popup_cmd_copy_image_location (EggAction *action, + EphyWindow *window); + +void popup_cmd_save_background_as (EggAction *action, + EphyWindow *window); + +void popup_cmd_open_frame (EggAction *action, + EphyWindow *window); + +void popup_cmd_open_image (EggAction *action, + EphyWindow *window); + +void popup_cmd_download_link (EggAction *action, + EphyWindow *window); + +void popup_cmd_save_image_as (EggAction *action, + EphyWindow *window); -void popup_cmd_view_source (BonoboUIComponent *uic, - EphyEmbedPopup *popup, - const char* verbname); diff --git a/src/ppview-toolbar.c b/src/ppview-toolbar.c index 06b2cbb6e..fea06c2d7 100755 --- a/src/ppview-toolbar.c +++ b/src/ppview-toolbar.c @@ -22,6 +22,7 @@ #include "ephy-bonobo-extensions.h" #include "ephy-string.h" #include "ephy-gui.h" +#include "egg-menu-merge.h" #include <string.h> #include <bonobo/bonobo-i18n.h> @@ -63,48 +64,68 @@ static GObjectClass *parent_class = NULL; struct PPViewToolbarPrivate { EphyWindow *window; - BonoboUIComponent *ui_component; - gboolean visibility; - EmbedChromeMask old_chrome; + EggMenuMerge *ui_merge; + EggActionGroup *action_group; + guint ui_id; int current_page; }; static void -toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname); +toolbar_cmd_ppv_goto_first (EggMenuMerge *merge, + PPViewToolbar *t); static void -toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname); +toolbar_cmd_ppv_goto_last (EggMenuMerge *merge, + PPViewToolbar *t); static void -toolbar_cmd_ppv_go_back (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname); +toolbar_cmd_ppv_go_back (EggMenuMerge *merge, + PPViewToolbar *t); static void -toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname); +toolbar_cmd_ppv_go_forward (EggMenuMerge *merge, + PPViewToolbar *t); static void -toolbar_cmd_ppv_close (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname); - -BonoboUIVerb ppview_toolbar_verbs [] = { - BONOBO_UI_VERB ("PPVGotoFirst", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_first), - BONOBO_UI_VERB ("PPVGotoLast", (BonoboUIVerbFn)toolbar_cmd_ppv_goto_last), - BONOBO_UI_VERB ("PPVGoBack", (BonoboUIVerbFn)toolbar_cmd_ppv_go_back), - BONOBO_UI_VERB ("PPVGoForward", (BonoboUIVerbFn)toolbar_cmd_ppv_go_forward), - BONOBO_UI_VERB ("PPVClose", (BonoboUIVerbFn)toolbar_cmd_ppv_close), - - BONOBO_UI_VERB_END +toolbar_cmd_ppv_close (EggMenuMerge *merge, + PPViewToolbar *t); + +static EggActionGroupEntry entries [] = { + { "PPVGotoFirst", N_("First"), + GTK_STOCK_GOTO_FIRST, NULL, + N_("Go to the first page"), + (GCallback)toolbar_cmd_ppv_goto_first, NULL }, + { "PPVGotoLast", N_("Last"), + GTK_STOCK_GOTO_LAST, NULL, + N_("Go to the last page"), + (GCallback)toolbar_cmd_ppv_goto_last, NULL }, + { "PPVGoBack", N_("Previous"), + GTK_STOCK_GO_BACK, NULL, + N_("Go to the previous page"), + (GCallback)toolbar_cmd_ppv_go_back, NULL }, + { "PPVGoForward", N_("Next"), + GTK_STOCK_GO_FORWARD, NULL, + N_("Go to next page"), + (GCallback)toolbar_cmd_ppv_go_forward, NULL }, + { "PPVClose", N_("Close"), + GTK_STOCK_CLOSE, NULL, + N_("Close print preview"), + (GCallback)toolbar_cmd_ppv_close, NULL }, }; - -GType +static guint n_entries = G_N_ELEMENTS (entries); + +static const gchar *ui_info = +"<Root>\n" +" <dockitem name=\"PPViewToolbar\">\n" +" <toolitem name=\"PPVGotoFirstItem\" verb=\"PPVGotoFirst\" />\n" +" <toolitem name=\"PPVGotoLastItem\" verb=\"PPVGotoLast\" />\n" +" <toolitem name=\"PPVGoBackItem\"verb=\"PPVGoBack\" />\n" +" <toolitem name=\"PPVGoForwardItem\" verb=\"PPVGoForward\" />\n" +" <toolitem name=\"PPVClose\" verb=\"PPVClose\" />\n" +" </dockitem>\n" +"</Root>\n"; + +GType ppview_toolbar_get_type (void) { static GType ppview_toolbar_type = 0; @@ -192,22 +213,30 @@ ppview_toolbar_set_window (PPViewToolbar *t, EphyWindow *window) g_return_if_fail (t->priv->window == NULL); t->priv->window = window; - t->priv->ui_component = BONOBO_UI_COMPONENT - (t->priv->window->ui_component); - - bonobo_ui_component_add_verb_list_with_data (t->priv->ui_component, - ppview_toolbar_verbs, - t); + t->priv->ui_merge = EGG_MENU_MERGE (t->priv->window->ui_merge); + + t->priv->action_group = egg_action_group_new ("PPViewActions"); + egg_action_group_add_actions (t->priv->action_group, entries, n_entries); + egg_menu_merge_insert_action_group (t->priv->ui_merge, + t->priv->action_group, 0); + t->priv->ui_id = egg_menu_merge_add_ui_from_string + (t->priv->ui_merge, ui_info, -1, NULL); } static void ppview_toolbar_init (PPViewToolbar *t) { + int i; + t->priv = g_new0 (PPViewToolbarPrivate, 1); t->priv->window = NULL; - t->priv->ui_component = NULL; - t->priv->visibility = TRUE; + t->priv->ui_merge = NULL; + + for (i = 0; i < n_entries; i++) + { + entries[i].user_data = t; + } } static void @@ -221,6 +250,8 @@ ppview_toolbar_finalize (GObject *object) t = PPVIEW_TOOLBAR (object); g_return_if_fail (t->priv != NULL); + egg_menu_merge_remove_ui (t->priv->ui_merge, t->priv->ui_id); + g_object_unref (t->priv->action_group); g_free (t->priv); @@ -241,13 +272,6 @@ ppview_toolbar_new (EphyWindow *window) return t; } -void -ppview_toolbar_set_old_chrome (PPViewToolbar *t, - EmbedChromeMask chrome) -{ - t->priv->old_chrome = chrome; -} - static void toolbar_update_sensitivity (PPViewToolbar *t) { @@ -260,7 +284,7 @@ toolbar_update_sensitivity (PPViewToolbar *t) ephy_embed_print_preview_num_pages (embed, &pages); c_page = t->priv->current_page; - +/* ephy_bonobo_set_sensitive (t->priv->ui_component, PPV_GO_BACK_PATH, c_page > 1); ephy_bonobo_set_sensitive (t->priv->ui_component, @@ -269,30 +293,12 @@ toolbar_update_sensitivity (PPViewToolbar *t) PPV_GO_FORWARD_PATH, c_page < pages); ephy_bonobo_set_sensitive (t->priv->ui_component, PPV_GOTO_LAST_PATH, c_page < pages); -} - -void -ppview_toolbar_set_visibility (PPViewToolbar *t, gboolean visibility) -{ - if (visibility == t->priv->visibility) return; - - t->priv->visibility = visibility; - - if (visibility) - { - t->priv->current_page = 1; - toolbar_update_sensitivity (t); - } - - ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component), - "/PrintPreview", - !visibility); + */ } static void -toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname) +toolbar_cmd_ppv_goto_first (EggMenuMerge *merge, + PPViewToolbar *t) { EphyWindow *window = t->priv->window; EphyEmbed *embed; @@ -308,9 +314,8 @@ toolbar_cmd_ppv_goto_first (BonoboUIComponent *uic, } static void -toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname) +toolbar_cmd_ppv_goto_last (EggMenuMerge *merge, + PPViewToolbar *t) { EphyWindow *window = t->priv->window; EphyEmbed *embed; @@ -329,9 +334,8 @@ toolbar_cmd_ppv_goto_last (BonoboUIComponent *uic, } static void -toolbar_cmd_ppv_go_back (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname) +toolbar_cmd_ppv_go_back (EggMenuMerge *merge, + PPViewToolbar *t) { EphyWindow *window = t->priv->window; EphyEmbed *embed; @@ -349,9 +353,8 @@ toolbar_cmd_ppv_go_back (BonoboUIComponent *uic, } static void -toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname) +toolbar_cmd_ppv_go_forward (EggMenuMerge *merge, + PPViewToolbar *t) { EphyWindow *window = t->priv->window; EphyEmbed *embed; @@ -369,20 +372,8 @@ toolbar_cmd_ppv_go_forward (BonoboUIComponent *uic, } static void -toolbar_cmd_ppv_close (BonoboUIComponent *uic, - PPViewToolbar *t, - const char* verbname) +toolbar_cmd_ppv_close (EggMenuMerge *merge, + PPViewToolbar *t) { - EphyWindow *window = t->priv->window; - EphyEmbed *embed; - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - ephy_window_set_chrome (window, t->priv->old_chrome); - - ephy_embed_print_preview_close (embed); - - toolbar_update_sensitivity (t); } diff --git a/src/ppview-toolbar.h b/src/ppview-toolbar.h index 3e6a4b504..35356a0e5 100644 --- a/src/ppview-toolbar.h +++ b/src/ppview-toolbar.h @@ -52,12 +52,6 @@ GType ppview_toolbar_get_type (void); PPViewToolbar *ppview_toolbar_new (EphyWindow *window); -void ppview_toolbar_set_visibility (PPViewToolbar *t, - gboolean visibility); - -void ppview_toolbar_set_old_chrome (PPViewToolbar *t, - EmbedChromeMask chrome); - G_END_DECLS #endif diff --git a/src/statusbar.c b/src/statusbar.c index 8ac84cfb9..8ff6b4402 100755 --- a/src/statusbar.c +++ b/src/statusbar.c @@ -18,7 +18,6 @@ #include "statusbar.h" #include "ephy-stock-icons.h" -#include "ephy-bonobo-extensions.h" #include <string.h> #include <time.h> @@ -27,45 +26,22 @@ #include <gtk/gtkimage.h> #include <gtk/gtkframe.h> #include <gtk/gtktooltips.h> -#include <bonobo/bonobo-window.h> -#include <bonobo/bonobo-control.h> static void statusbar_class_init (StatusbarClass *klass); static void statusbar_init (Statusbar *t); static void statusbar_finalize (GObject *object); -static void -statusbar_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void -statusbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void -statusbar_set_window (Statusbar *t, EphyWindow *window); - -enum -{ - PROP_0, - PROP_EPHY_WINDOW -}; static GObjectClass *parent_class = NULL; struct StatusbarPrivate { - EphyWindow *window; - BonoboUIComponent *ui_component; GtkWidget *security_icon; GtkWidget *progress; GtkTooltips *tooltips; GtkWidget *security_evbox; - gboolean visibility; }; -GType +GType statusbar_get_type (void) { static GType statusbar_type = 0; @@ -85,7 +61,7 @@ statusbar_get_type (void) (GInstanceInitFunc) statusbar_init }; - statusbar_type = g_type_register_static (G_TYPE_OBJECT, + statusbar_type = g_type_register_static (GTK_TYPE_STATUSBAR, "Statusbar", &our_info, 0); } @@ -102,55 +78,12 @@ statusbar_class_init (StatusbarClass *klass) parent_class = g_type_class_peek_parent (klass); object_class->finalize = statusbar_finalize; - object_class->set_property = statusbar_set_property; - object_class->get_property = statusbar_get_property; - - g_object_class_install_property (object_class, - PROP_EPHY_WINDOW, - g_param_spec_object ("EphyWindow", - "EphyWindow", - "Parent window", - EPHY_WINDOW_TYPE, - G_PARAM_READWRITE)); -} - -static void -statusbar_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - Statusbar *s = STATUSBAR (object); - - switch (prop_id) - { - case PROP_EPHY_WINDOW: - statusbar_set_window (s, g_value_get_object (value)); - break; - } -} - -static void -statusbar_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - Statusbar *s = STATUSBAR (object); - - switch (prop_id) - { - case PROP_EPHY_WINDOW: - g_value_set_object (value, s->priv->window); - break; - } } static void create_statusbar_security_icon (Statusbar *s) { GtkWidget *security_frame; - BonoboControl *control; security_frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (security_frame), @@ -162,61 +95,38 @@ create_statusbar_security_icon (Statusbar *s) GTK_WIDGET (s->priv->security_evbox)); gtk_container_add (GTK_CONTAINER (s->priv->security_evbox), GTK_WIDGET (s->priv->security_icon)); - /* - g_signal_connect (G_OBJECT (security_eventbox), - "button_release_event", - GTK_SIGNAL_FUNC - (security_icon_button_release_cb), t); - */ - - control = bonobo_control_new (security_frame); - bonobo_ui_component_object_set (s->priv->ui_component, - "/status/SecurityIconWrapper", - BONOBO_OBJREF (control), - NULL); - bonobo_object_unref (control); statusbar_set_security_state (s, FALSE, NULL); gtk_widget_show_all (security_frame); + + gtk_box_pack_start (GTK_BOX (s), + GTK_WIDGET (security_frame), + FALSE, TRUE, 0); } static void create_statusbar_progress (Statusbar *s) { - BonoboControl *control; - s->priv->progress = gtk_progress_bar_new (); - - control = bonobo_control_new (s->priv->progress); - bonobo_ui_component_object_set (s->priv->ui_component, - "/status/ProgressWrapper", - BONOBO_OBJREF (control), - NULL); - gtk_widget_show_all (s->priv->progress); -} - -static void -statusbar_set_window (Statusbar *s, EphyWindow *window) -{ - g_return_if_fail (s->priv->window == NULL); - s->priv->window = window; - s->priv->ui_component = BONOBO_UI_COMPONENT - (s->priv->window->ui_component); - - create_statusbar_progress (s); - create_statusbar_security_icon (s); + gtk_box_pack_start (GTK_BOX (s), + GTK_WIDGET (s->priv->progress), + FALSE, TRUE, 0); } static void statusbar_init (Statusbar *t) { t->priv = g_new0 (StatusbarPrivate, 1); - t->priv->visibility = TRUE; t->priv->tooltips = gtk_tooltips_new (); + + gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (t), FALSE); + + create_statusbar_progress (t); + create_statusbar_security_icon (t); } static void @@ -238,34 +148,18 @@ statusbar_finalize (GObject *object) G_OBJECT_CLASS (parent_class)->finalize (object); } -Statusbar * -statusbar_new (EphyWindow *window) +GtkWidget * +statusbar_new (void) { - Statusbar *t; - - t = STATUSBAR (g_object_new (STATUSBAR_TYPE, - "EphyWindow", window, - NULL)); + GtkWidget *t; - g_return_val_if_fail (t->priv != NULL, NULL); + t = GTK_WIDGET (g_object_new (STATUSBAR_TYPE, + NULL)); return t; } void -statusbar_set_visibility (Statusbar *t, - gboolean visibility) -{ - if (visibility == t->priv->visibility) return; - - t->priv->visibility = visibility; - - ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component), - "/status", - !visibility); -} - -void statusbar_set_security_state (Statusbar *t, gboolean state, const char *tooltip) @@ -302,20 +196,9 @@ void statusbar_set_message (Statusbar *s, const char *message) { - g_return_if_fail (BONOBO_IS_UI_COMPONENT(s->priv->ui_component)); g_return_if_fail (message != NULL); - /* Bonobo doesnt like 0 length messages */ - if (g_utf8_strlen (message, -1) == 0) - { - message = " "; - } - - if (bonobo_ui_component_get_container (s->priv->ui_component)) /* should not do this here... */ - { - bonobo_ui_component_set_status (s->priv->ui_component, - message, - NULL); - } + gtk_statusbar_pop (GTK_STATUSBAR (s), 0); + gtk_statusbar_push (GTK_STATUSBAR (s), 0, message); } diff --git a/src/statusbar.h b/src/statusbar.h index 590b89394..27af4b315 100644 --- a/src/statusbar.h +++ b/src/statusbar.h @@ -19,13 +19,10 @@ #ifndef STATUSBAR_H #define STATUSBAR_H -#include "ephy-window.h" +#include <gtk/gtkstatusbar.h> G_BEGIN_DECLS -#include <glib-object.h> -#include <glib.h> - typedef struct Statusbar Statusbar; typedef struct StatusbarClass StatusbarClass; @@ -39,21 +36,18 @@ typedef struct StatusbarPrivate StatusbarPrivate; struct Statusbar { - GObject parent; + GtkStatusbar parent; StatusbarPrivate *priv; }; struct StatusbarClass { - GObjectClass parent_class; + GtkStatusbarClass parent_class; }; GType statusbar_get_type (void); -Statusbar *statusbar_new (EphyWindow *window); - -void statusbar_set_visibility (Statusbar *s, - gboolean visibility); +GtkWidget *statusbar_new (void); void statusbar_set_security_state (Statusbar *s, gboolean state, diff --git a/src/toolbar.c b/src/toolbar.c index 27c2606f2..51cf64b5f 100755 --- a/src/toolbar.c +++ b/src/toolbar.c @@ -18,48 +18,22 @@ */ #include "toolbar.h" -#include "ephy-spinner.h" -#include "ephy-window.h" -#include "ephy-bonobo-extensions.h" -#include "ephy-string.h" -#include "ephy-gui.h" -#include "ephy-location-entry.h" +#include "egg-menu-merge.h" +#include "ephy-file-helpers.h" #include "ephy-shell.h" +#include "ephy-location-entry.h" #include "ephy-dnd.h" -#include "ephy-toolbar-bonobo-view.h" -#include "ephy-toolbar-item-factory.h" -#include "ephy-prefs.h" -#include "eel-gconf-extensions.h" -#include "ephy-navigation-button.h" -#include "ephy-debug.h" - -#include <string.h> -#include <bonobo/bonobo-i18n.h> -#include <bonobo/bonobo-window.h> -#include <bonobo/bonobo-control.h> -#include <bonobo/bonobo-ui-toolbar-button-item.h> -#include <bonobo/bonobo-property-bag.h> -#include <gtk/gtkentry.h> -#include <gtk/gtkmenu.h> - -#define DEFAULT_TOOLBAR_SETUP \ - "back_menu=navigation_button(direction=back,arrow=TRUE);" \ - "forward_menu=navigation_button(direction=forward,arrow=TRUE);" \ - "stop=std_toolitem(item=stop);" \ - "reload=std_toolitem(item=reload);" \ - "home=std_toolitem(item=home);" \ - "favicon=favicon;" \ - "location=location;" \ - "spinner=spinner;" - -#define ZOOM_DELAY 50 +#include "ephy-spinner.h" +#include "ephy-spinner-action.h" +#include "ephy-location-action.h" +#include "ephy-favicon-action.h" +#include "ephy-navigation-action.h" +#include "window-commands.h" static void toolbar_class_init (ToolbarClass *klass); static void toolbar_init (Toolbar *t); static void toolbar_finalize (GObject *object); static void toolbar_set_window (Toolbar *t, EphyWindow *window); -static void toolbar_get_widgets (Toolbar *t); -static void toolbar_changed_cb (EphyToolbar *gt, Toolbar *t); static void toolbar_set_property (GObject *object, guint prop_id, @@ -78,31 +52,17 @@ enum PROP_EPHY_WINDOW }; -enum -{ - TOOLBAR_ITEM_STYLE_PROP, - TOOLBAR_ITEM_ORIENTATION_PROP, - TOOLBAR_ITEM_PRIORITY_PROP -}; - static GObjectClass *parent_class = NULL; struct ToolbarPrivate { EphyWindow *window; - BonoboUIComponent *ui_component; - EphyTbBonoboView *bview; - - GtkWidget *spinner; + EggMenuMerge *ui_merge; + EggActionGroup *action_group; gboolean visibility; GtkWidget *location_entry; - GSList *navigation_buttons; - GtkTooltips *tooltips; + GtkWidget *spinner; GtkWidget *favicon; - GtkWidget *favicon_ebox; - GtkWidget *zoom_spinbutton; - guint zoom_timeout_id; - gboolean zoom_lock; }; GType @@ -125,7 +85,7 @@ toolbar_get_type (void) (GInstanceInitFunc) toolbar_init }; - toolbar_type = g_type_register_static (EPHY_TYPE_TOOLBAR, + toolbar_type = g_type_register_static (G_TYPE_OBJECT, "Toolbar", &our_info, 0); } @@ -153,8 +113,6 @@ toolbar_class_init (ToolbarClass *klass) "Parent window", EPHY_WINDOW_TYPE, G_PARAM_READWRITE)); - ephy_toolbar_item_register_type - ("navigation_button", (EphyTbItemConstructor) ephy_navigation_button_new); } static void @@ -190,287 +148,108 @@ toolbar_get_property (GObject *object, } static void -toolbar_location_url_activate_cb (EphyLocationEntry *entry, - const char *content, - const char *target, - EphyWindow *window) +toolbar_setup_widgets (Toolbar *t) { - EphyBookmarks *bookmarks; - - bookmarks = ephy_shell_get_bookmarks (ephy_shell); - - if (!content) - { - ephy_window_load_url (window, target); - } - else - { - char *url; - - url = ephy_bookmarks_solve_smart_url - (bookmarks, target, content); - g_return_if_fail (url != NULL); - ephy_window_load_url (window, url); - g_free (url); - } + egg_menu_merge_add_ui_from_file (t->priv->ui_merge, + ephy_file ("epiphany-toolbar.xml"), NULL); + egg_menu_merge_ensure_update (t->priv->ui_merge); } static void -each_url_get_data_binder (EphyDragEachSelectedItemDataGet iteratee, - gpointer iterator_context, gpointer data) +add_widget (EggMenuMerge *merge, GtkWidget *widget, EphyWindow *window) { - const char *location; - EphyTab *tab; - EphyWindow *window = EPHY_WINDOW(iterator_context); - - tab = ephy_window_get_active_tab (window); - location = ephy_tab_get_location (tab); - - iteratee (location, -1, -1, -1, -1, data); } static void -favicon_drag_data_get_cb (GtkWidget *widget, - GdkDragContext *context, - GtkSelectionData *selection_data, - guint info, - guint32 time, - EphyWindow *window) +go_location_cb (EggAction *action, char *location, EphyWindow *window) { - g_assert (widget != NULL); - g_return_if_fail (context != NULL); - - ephy_dnd_drag_data_get (widget, context, selection_data, - info, time, window, each_url_get_data_binder); -} + EphyEmbed *embed; -static void -toolbar_setup_favicon_ebox (Toolbar *t, GtkWidget *w) -{ - ToolbarPrivate *p = t->priv; + embed = ephy_window_get_active_embed (window); + g_return_if_fail (embed != NULL); - g_return_if_fail (w == p->favicon_ebox); - - p->favicon = g_object_ref (gtk_image_new ()); - gtk_container_add (GTK_CONTAINER (p->favicon_ebox), p->favicon); - gtk_container_set_border_width (GTK_CONTAINER (p->favicon_ebox), 2); - - ephy_dnd_url_drag_source_set (p->favicon_ebox); - - g_signal_connect (G_OBJECT (p->favicon_ebox), - "drag_data_get", - G_CALLBACK (favicon_drag_data_get_cb), - p->window); - gtk_widget_show_all (p->favicon_ebox); -} - -static gboolean -toolbar_zoom_timeout_cb (gpointer data) -{ - Toolbar *t = data; - gint zoom = toolbar_get_zoom (t); - - g_return_val_if_fail (IS_EPHY_WINDOW (t->priv->window), FALSE); - - ephy_window_set_zoom (t->priv->window, zoom); - - return FALSE; -} - -static void -toolbar_zoom_spinbutton_value_changed_cb (GtkSpinButton *sb, Toolbar *t) -{ - ToolbarPrivate *p = t->priv; - if (p->zoom_timeout_id != 0) - { - g_source_remove (p->zoom_timeout_id); - } - if (!p->zoom_lock) - { - p->zoom_timeout_id = g_timeout_add (ZOOM_DELAY, toolbar_zoom_timeout_cb, t); - } -} - -static void -toolbar_setup_zoom_spinbutton (Toolbar *t, GtkWidget *w) -{ - g_signal_connect (w, "value_changed", - G_CALLBACK (toolbar_zoom_spinbutton_value_changed_cb), t); - gtk_tooltips_set_tip (t->priv->tooltips, w, _("Zoom"), NULL); + ephy_embed_load_url (embed, location); } static void -toolbar_setup_location_entry (Toolbar *t, GtkWidget *w) -{ - EphyAutocompletion *ac = ephy_shell_get_autocompletion (ephy_shell); - EphyLocationEntry *e; - - g_return_if_fail (w == t->priv->location_entry); - g_return_if_fail (EPHY_IS_LOCATION_ENTRY (w)); - - e = EPHY_LOCATION_ENTRY (w); - ephy_location_entry_set_autocompletion (e, ac); - - g_signal_connect (e, "activated", - GTK_SIGNAL_FUNC(toolbar_location_url_activate_cb), - t->priv->window); +toolbar_setup_actions (Toolbar *t) +{ + EggAction *action; + + t->priv->action_group = egg_action_group_new ("SpecialToolbarActions"); + + action = g_object_new (EPHY_TYPE_NAVIGATION_ACTION, + "name", "NavigationBack", + "label", _("Back"), + "stock_id", GTK_STOCK_GO_BACK, + "window", t->priv->window, + "direction", EPHY_NAVIGATION_DIRECTION_BACK, + NULL); + g_signal_connect (action, "activate", + G_CALLBACK (window_cmd_go_back), t->priv->window); + egg_action_group_add_action (t->priv->action_group, action); + g_object_unref (action); + + action = g_object_new (EPHY_TYPE_NAVIGATION_ACTION, + "name", "NavigationForward", + "label", _("Forward"), + "stock_id", GTK_STOCK_GO_FORWARD, + "window", t->priv->window, + "direction", EPHY_NAVIGATION_DIRECTION_FORWARD, + NULL); + g_signal_connect (action, "activate", + G_CALLBACK (window_cmd_go_forward), t->priv->window); + egg_action_group_add_action (t->priv->action_group, action); + g_object_unref (action); + + action = g_object_new (EPHY_TYPE_NAVIGATION_ACTION, + "name", "NavigationUp", + "label", _("Up"), + "window", t->priv->window, + "direction", EPHY_NAVIGATION_DIRECTION_UP, + "stock_id", GTK_STOCK_GO_UP, + NULL); + g_signal_connect (action, "activate", + G_CALLBACK (window_cmd_go_up), t->priv->window); + egg_action_group_add_action (t->priv->action_group, action); + g_object_unref (action); + + action = g_object_new (EPHY_TYPE_SPINNER_ACTION, + "name", "Spinner", + NULL); + egg_action_group_add_action (t->priv->action_group, action); + g_object_unref (action); + + action = g_object_new (EPHY_TYPE_LOCATION_ACTION, + "name", "Location", + NULL); + g_signal_connect (action, "go_location", + G_CALLBACK (go_location_cb), t->priv->window); + egg_action_group_add_action (t->priv->action_group, action); + g_object_unref (action); + + action = g_object_new (EPHY_TYPE_FAVICON_ACTION, + "name", "Favicon", + "window", t->priv->window, + NULL); + egg_action_group_add_action (t->priv->action_group, action); + g_object_unref (action); } static void -toolbar_setup_spinner (Toolbar *t, GtkWidget *w) -{ - ToolbarPrivate *p = t->priv; - GtkWidget *spinner; - - g_return_if_fail (w == p->spinner); - - /* build the spinner and insert it into the box */ - spinner = ephy_spinner_new (); - ephy_spinner_set_small_mode (EPHY_SPINNER (spinner), TRUE); - gtk_container_add (GTK_CONTAINER (p->spinner), spinner); - gtk_widget_show (spinner); - - /* don't care about the box anymore */ - g_object_unref (p->spinner); - p->spinner = g_object_ref (spinner); -} - - -static void toolbar_set_window (Toolbar *t, EphyWindow *window) { g_return_if_fail (t->priv->window == NULL); t->priv->window = window; - t->priv->ui_component = g_object_ref (t->priv->window->ui_component); - - ephy_tb_bonobo_view_set_path (t->priv->bview, t->priv->ui_component, "/Toolbar"); - - toolbar_get_widgets (t); -} - -static void -toolbar_get_widgets (Toolbar *t) -{ - ToolbarPrivate *p; - EphyToolbar *gt; - EphyTbItem *it; - GSList *li; - const gchar *nav_buttons_ids[] = {"back", "back_menu", "up", "up_menu", "forward", "forward_menu" }; - guint i; - - LOG ("in toolbar_get_widgets"); - - g_return_if_fail (IS_TOOLBAR (t)); - p = t->priv; - g_return_if_fail (IS_EPHY_WINDOW (p->window)); - g_return_if_fail (BONOBO_IS_UI_COMPONENT (p->ui_component)); - - /* release all the widgets */ - - for (li = p->navigation_buttons; li; li = li->next) - { - g_object_unref (li->data); - } - g_slist_free (p->navigation_buttons); - p->navigation_buttons = NULL; - - if (p->favicon_ebox) - { - g_object_unref (p->favicon_ebox); - p->favicon_ebox = NULL; - } - - if (p->favicon) - { - g_object_unref (p->favicon); - p->favicon = NULL; - } - - if (p->location_entry) - { - g_object_unref (p->location_entry); - p->location_entry = NULL; - } - - if (p->spinner) - { - g_object_unref (p->spinner); - p->spinner = NULL; - } - - if (p->zoom_spinbutton) - { - g_object_unref (p->zoom_spinbutton); - p->zoom_spinbutton = NULL; - } - - gt = EPHY_TOOLBAR (t); - - for (i = 0; i < G_N_ELEMENTS (nav_buttons_ids); ++i) - { - it = ephy_toolbar_get_item_by_id (gt, nav_buttons_ids[i]); - if (it) - { - if (EPHY_IS_NAVIGATION_BUTTON (it)) - { - LOG ("got a navigation button") - p->navigation_buttons = g_slist_prepend (p->navigation_buttons, g_object_ref (it)); - if (p->window) - { - ephy_tbi_set_window (EPHY_TBI (it), p->window); - } - } - else - { - g_warning ("An unexpected button has been found in your toolbar. " - "Maybe your setup is too old."); - } - } - } - - it = ephy_toolbar_get_item_by_id (gt, "location"); - if (it) - { - p->location_entry = ephy_tb_item_get_widget (it); - g_object_ref (p->location_entry); - toolbar_setup_location_entry (t, p->location_entry); - - LOG ("got a location entry") - } - - it = ephy_toolbar_get_item_by_id (gt, "favicon"); - if (it) - { - p->favicon_ebox = ephy_tb_item_get_widget (it); - g_object_ref (p->favicon_ebox); - toolbar_setup_favicon_ebox (t, p->favicon_ebox); - - LOG ("got a favicon ebox") - } - - it = ephy_toolbar_get_item_by_id (gt, "spinner"); - if (it) - { - p->spinner = ephy_tb_item_get_widget (it); - g_object_ref (p->spinner); - toolbar_setup_spinner (t, p->spinner); - - LOG ("got a spinner") - } - - it = ephy_toolbar_get_item_by_id (gt, "zoom"); - if (it) - { - p->zoom_spinbutton = ephy_tb_item_get_widget (it); - g_object_ref (p->zoom_spinbutton); - toolbar_setup_zoom_spinbutton (t, p->zoom_spinbutton); - - LOG ("got a zoom control") - } - - /* update the controls */ - ephy_window_update_all_controls (p->window); + t->priv->ui_merge = EGG_MENU_MERGE (window->ui_merge); + g_signal_connect (t->priv->ui_merge, "add_widget", + G_CALLBACK (add_widget), t); + + toolbar_setup_actions (t); + egg_menu_merge_insert_action_group (t->priv->ui_merge, + t->priv->action_group, 1); + toolbar_setup_widgets (t); } static void @@ -479,38 +258,8 @@ toolbar_init (Toolbar *t) t->priv = g_new0 (ToolbarPrivate, 1); t->priv->window = NULL; - t->priv->ui_component = NULL; - t->priv->navigation_buttons = NULL; + t->priv->ui_merge = NULL; t->priv->visibility = TRUE; - t->priv->tooltips = gtk_tooltips_new (); - g_object_ref (t->priv->tooltips); - gtk_object_sink (GTK_OBJECT (t->priv->tooltips)); - - if (!ephy_toolbar_listen_to_gconf (EPHY_TOOLBAR (t), CONF_TOOLBAR_SETUP)) - { - /* FIXME: make this a dialog? */ - g_warning ("An incorrect toolbar configuration has been found, resetting to the default"); - - /* this is to make sure we get a toolbar, even if the - setup is wrong or there is no schema */ - eel_gconf_set_string (CONF_TOOLBAR_SETUP, DEFAULT_TOOLBAR_SETUP); - } - - g_signal_connect (t, "changed", G_CALLBACK (toolbar_changed_cb), t); - - t->priv->bview = ephy_tb_bonobo_view_new (); - ephy_tb_bonobo_view_set_toolbar (t->priv->bview, EPHY_TOOLBAR (t)); -} - -static void -toolbar_changed_cb (EphyToolbar *gt, Toolbar *t) -{ - g_return_if_fail (gt == EPHY_TOOLBAR (t)); - - if (t->priv->window) - { - toolbar_get_widgets (t); - } } static void @@ -518,7 +267,6 @@ toolbar_finalize (GObject *object) { Toolbar *t; ToolbarPrivate *p; - GSList *li; g_return_if_fail (object != NULL); g_return_if_fail (IS_TOOLBAR (object)); @@ -528,24 +276,7 @@ toolbar_finalize (GObject *object) g_return_if_fail (p != NULL); - if (p->location_entry) g_object_unref (p->location_entry); - if (p->favicon_ebox) g_object_unref (p->favicon_ebox); - if (p->favicon) g_object_unref (p->favicon); - if (p->spinner) g_object_unref (p->spinner); - if (p->tooltips) g_object_unref (p->tooltips); - if (p->zoom_spinbutton) g_object_unref (p->zoom_spinbutton); - if (p->zoom_timeout_id != 0) - { - g_source_remove (p->zoom_timeout_id); - } - - for (li = t->priv->navigation_buttons; li; li = li->next) - { - g_object_unref (li->data); - } - g_slist_free (t->priv->navigation_buttons); - - g_object_unref (t->priv->bview); + g_object_unref (t->priv->action_group); g_free (t->priv); @@ -569,165 +300,106 @@ toolbar_new (EphyWindow *window) void toolbar_set_visibility (Toolbar *t, gboolean visibility) { - if (visibility == t->priv->visibility) return; - - t->priv->visibility = visibility; - - ephy_bonobo_set_hidden (BONOBO_UI_COMPONENT(t->priv->ui_component), - "/Toolbar", - !visibility); } void toolbar_activate_location (Toolbar *t) { - if (t->priv->location_entry) - { - ephy_location_entry_activate - (EPHY_LOCATION_ENTRY(t->priv->location_entry)); - } + EggAction *action; + GtkWidget *location; + + action = egg_action_group_get_action + (t->priv->action_group, "Location"); + location = ephy_location_action_get_widget + (EPHY_LOCATION_ACTION (action)); + g_return_if_fail (location != NULL); + + ephy_location_entry_activate + (EPHY_LOCATION_ENTRY(location)); } void toolbar_spinner_start (Toolbar *t) { - if (t->priv->spinner) - { - ephy_spinner_start (EPHY_SPINNER(t->priv->spinner)); - } + EggActionGroup *action_group; + EggAction *action; + + action_group = t->priv->action_group; + action = egg_action_group_get_action (action_group, "Spinner"); + g_object_set (action, "throbbing", TRUE, NULL); } void toolbar_spinner_stop (Toolbar *t) { - if (t->priv->spinner) - { - ephy_spinner_stop (EPHY_SPINNER(t->priv->spinner)); - } -} + EggActionGroup *action_group; + EggAction *action; -static void -toolbar_navigation_button_set_sensitive (Toolbar *t, EphyNavigationDirection d, gboolean sensitivity) -{ - GSList *li; - ToolbarPrivate *p = t->priv; - - for (li = p->navigation_buttons; li; li = li->next) - { - EphyNavigationButton *b = EPHY_NAVIGATION_BUTTON (li->data); - if (ephy_navigation_button_get_direction (b) == d) - { - ephy_navigation_button_set_sensitive (b, sensitivity); - } - } -} - -void -toolbar_button_set_sensitive (Toolbar *t, - ToolbarButtonID id, - gboolean sensitivity) -{ - switch (id) - { - case TOOLBAR_BACK_BUTTON: - toolbar_navigation_button_set_sensitive (t, EPHY_NAVIGATION_DIRECTION_BACK, sensitivity); - break; - case TOOLBAR_FORWARD_BUTTON: - toolbar_navigation_button_set_sensitive (t, EPHY_NAVIGATION_DIRECTION_FORWARD, sensitivity); - break; - case TOOLBAR_UP_BUTTON: - toolbar_navigation_button_set_sensitive (t, EPHY_NAVIGATION_DIRECTION_UP, sensitivity); - break; - case TOOLBAR_STOP_BUTTON: - ephy_bonobo_set_sensitive (t->priv->ui_component, - "/commands/GoStop", - sensitivity); - break; - } + action_group = t->priv->action_group; + action = egg_action_group_get_action (action_group, "Spinner"); + g_object_set (action, "throbbing", FALSE, NULL); } void toolbar_set_location (Toolbar *t, - const char *location) + const char *alocation) { + EggAction *action; + GtkWidget *location; + + action = egg_action_group_get_action + (t->priv->action_group, "Location"); + location = ephy_location_action_get_widget + (EPHY_LOCATION_ACTION (action)); g_return_if_fail (location != NULL); - if (t->priv->location_entry) - { - ephy_location_entry_set_location - (EPHY_LOCATION_ENTRY (t->priv->location_entry), location); - } + ephy_location_entry_set_location + (EPHY_LOCATION_ENTRY (location), alocation); } void toolbar_update_favicon (Toolbar *t) { - GdkPixbuf *pixbuf = NULL; - EphyFaviconCache *cache; EphyTab *tab; const char *url; + EggActionGroup *action_group; + EggAction *action; - cache = ephy_embed_shell_get_favicon_cache (EPHY_EMBED_SHELL (ephy_shell)); tab = ephy_window_get_active_tab (t->priv->window); url = ephy_tab_get_favicon_url (tab); - - if (url) - { - pixbuf = ephy_favicon_cache_get (cache, url); - } - - if (pixbuf) - { - gtk_image_set_from_pixbuf (GTK_IMAGE (t->priv->favicon), pixbuf); - } - else - { - gtk_image_set_from_stock (GTK_IMAGE (t->priv->favicon), - GTK_STOCK_JUMP_TO, - GTK_ICON_SIZE_MENU); - } + action_group = t->priv->action_group; + action = egg_action_group_get_action (action_group, "Favicon"); + g_object_set (action, "icon", url, NULL); } char * toolbar_get_location (Toolbar *t) { - gchar *location; - if (t->priv->location_entry) - { - location = ephy_location_entry_get_location - (EPHY_LOCATION_ENTRY (t->priv->location_entry)); - } - else - { - location = g_strdup (""); - } - return location; -} + EggAction *action; + GtkWidget *location; -gint -toolbar_get_zoom (Toolbar *t) -{ - gint zoom; - if (t->priv->zoom_spinbutton) - { - zoom = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (t->priv->zoom_spinbutton)); - } - else - { - zoom = 100; - } - return zoom; + action = egg_action_group_get_action + (t->priv->action_group, "Location"); + location = ephy_location_action_get_widget + (EPHY_LOCATION_ACTION (action)); + g_return_val_if_fail (location != NULL, NULL); + + return ephy_location_entry_get_location + (EPHY_LOCATION_ENTRY (location)); } void -toolbar_set_zoom (Toolbar *t, gint zoom) -{ - ToolbarPrivate *p = t->priv; - if (p->zoom_spinbutton) - { - p->zoom_lock = TRUE; - gtk_spin_button_set_value (GTK_SPIN_BUTTON (p->zoom_spinbutton), zoom); - p->zoom_lock = FALSE; - } +toolbar_update_navigation_actions (Toolbar *t, gboolean back, gboolean forward, gboolean up) +{ + EggActionGroup *action_group; + EggAction *action; + + action_group = t->priv->action_group; + action = egg_action_group_get_action (action_group, "NavigationBack"); + g_object_set (action, "sensitive", !back, NULL); + action = egg_action_group_get_action (action_group, "NavigationForward"); + g_object_set (action, "sensitive", !forward, NULL); + action = egg_action_group_get_action (action_group, "NavigationUp"); + g_object_set (action, "sensitive", !up, NULL); } diff --git a/src/toolbar.h b/src/toolbar.h index 5764c14e1..63ebff824 100644 --- a/src/toolbar.h +++ b/src/toolbar.h @@ -22,7 +22,6 @@ #include "ephy-window.h" #include <glib-object.h> #include <glib.h> -#include "ephy-toolbar.h" G_BEGIN_DECLS @@ -36,23 +35,15 @@ typedef struct ToolbarClass ToolbarClass; typedef struct ToolbarPrivate ToolbarPrivate; -typedef enum -{ - TOOLBAR_BACK_BUTTON, - TOOLBAR_FORWARD_BUTTON, - TOOLBAR_STOP_BUTTON, - TOOLBAR_UP_BUTTON -} ToolbarButtonID; - struct Toolbar { - EphyToolbar parent_object; + GObject parent_object; ToolbarPrivate *priv; }; struct ToolbarClass { - EphyToolbarClass parent_class; + GObjectClass parent_class; }; GType toolbar_get_type (void); @@ -62,10 +53,6 @@ Toolbar *toolbar_new (EphyWindow *window); void toolbar_set_visibility (Toolbar *t, gboolean visibility); -void toolbar_button_set_sensitive (Toolbar *t, - ToolbarButtonID id, - gboolean sensitivity); - void toolbar_spinner_start (Toolbar *t); void toolbar_spinner_stop (Toolbar *t); @@ -75,14 +62,15 @@ char *toolbar_get_location (Toolbar *t); void toolbar_set_location (Toolbar *t, const char *location); -gint toolbar_get_zoom (Toolbar *t); - -void toolbar_set_zoom (Toolbar *t, gint zoom); - void toolbar_activate_location (Toolbar *t); void toolbar_update_favicon (Toolbar *t); +void toolbar_update_navigation_actions (Toolbar *t, + gboolean back, + gboolean forward, + gboolean up); + G_END_DECLS #endif diff --git a/src/window-commands.c b/src/window-commands.c index 0364a7d60..ece083b35 100644 --- a/src/window-commands.c +++ b/src/window-commands.c @@ -26,8 +26,6 @@ #include "ephy-prefs.h" #include "ephy-embed-utils.h" #include "pdm-dialog.h" -#include "toolbar.h" -#include "ephy-toolbar-editor.h" #include "ephy-bookmarks-editor.h" #include "ephy-new-bookmark.h" @@ -58,9 +56,8 @@ "separator;" void -window_cmd_edit_find (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_find (EggAction *action, + EphyWindow *window) { EphyDialog *dialog; dialog = ephy_window_get_find_dialog (window); @@ -78,9 +75,8 @@ print_dialog_preview_cb (PrintDialog *dialog, } void -window_cmd_file_print (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_print (EggAction *action, + EphyWindow *window) { EphyDialog *dialog; EphyEmbed *embed; @@ -99,9 +95,8 @@ window_cmd_file_print (BonoboUIComponent *uic, } void -window_cmd_go_back (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_go_back (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; @@ -112,9 +107,8 @@ window_cmd_go_back (BonoboUIComponent *uic, } void -window_cmd_go_up (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_go_up (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; @@ -125,9 +119,8 @@ window_cmd_go_up (BonoboUIComponent *uic, } void -window_cmd_file_send_to (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_send_to (EggAction *action, + EphyWindow *window) { char *url; EphyTab *tab; @@ -165,9 +158,8 @@ window_cmd_file_send_to (BonoboUIComponent *uic, } void -window_cmd_go_forward (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_go_forward (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; @@ -178,28 +170,8 @@ window_cmd_go_forward (BonoboUIComponent *uic, } void -window_cmd_go_go (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) -{ - Toolbar *tb; - - g_return_if_fail (IS_EPHY_WINDOW (window)); - - tb = ephy_window_get_toolbar (window); - - if (tb) - { - char *location = toolbar_get_location (tb); - ephy_window_load_url (window, location); - g_free (location); - } -} - -void -window_cmd_go_home (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_go_home (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; char *location; @@ -216,30 +188,15 @@ window_cmd_go_home (BonoboUIComponent *uic, } void -window_cmd_go_myportal (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) -{ - EphyEmbed *embed; - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - ephy_embed_load_url (embed, "myportal:"); -} - -void -window_cmd_go_location (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_go_location (EggAction *action, + EphyWindow *window) { ephy_window_activate_location (window); } void -window_cmd_go_stop (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_view_stop (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; @@ -250,9 +207,8 @@ window_cmd_go_stop (BonoboUIComponent *uic, } void -window_cmd_go_reload (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_view_reload (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; @@ -263,23 +219,8 @@ window_cmd_go_reload (BonoboUIComponent *uic, } void -window_cmd_new (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) -{ - EphyTab *tab; - - tab = ephy_window_get_active_tab (window); - - ephy_shell_new_tab (ephy_shell, window, tab, NULL, - EPHY_NEW_TAB_HOMEPAGE | - EPHY_NEW_TAB_JUMP); -} - -void -window_cmd_new_window (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_new_window (EggAction *action, + EphyWindow *window) { EphyTab *tab; @@ -292,9 +233,8 @@ window_cmd_new_window (BonoboUIComponent *uic, } void -window_cmd_new_tab (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_new_tab (EggAction *action, + EphyWindow *window) { EphyTab *tab; @@ -307,9 +247,8 @@ window_cmd_new_tab (BonoboUIComponent *uic, } void -window_cmd_bookmarks_edit (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_go_bookmarks (EggAction *action, + EphyWindow *window) { GtkWidget *dialog; EphyBookmarks *bookmarks; @@ -321,9 +260,8 @@ window_cmd_bookmarks_edit (BonoboUIComponent *uic, } void -window_cmd_bookmarks_add_default (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_add_bookmark (EggAction *action, + EphyWindow *window) { EphyTab *tab; EphyEmbed *embed; @@ -358,9 +296,8 @@ window_cmd_bookmarks_add_default (BonoboUIComponent *uic, } void -window_cmd_file_open (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_open (EggAction *action, + EphyWindow *window) { gchar *dir, *retDir; gchar *file = NULL; @@ -406,9 +343,8 @@ window_cmd_file_open (BonoboUIComponent *uic, } void -window_cmd_file_save_as (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_save_as (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; EphyEmbedPersist *persist; @@ -430,9 +366,8 @@ window_cmd_file_save_as (BonoboUIComponent *uic, } void -window_cmd_file_close_tab (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_close_tab (EggAction *action, + EphyWindow *window) { EphyTab *tab; @@ -443,17 +378,15 @@ window_cmd_file_close_tab (BonoboUIComponent *uic, } void -window_cmd_file_close_window (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_file_close_window (EggAction *action, + EphyWindow *window) { gtk_widget_destroy (GTK_WIDGET(window)); } void -window_cmd_edit_cut (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_cut (EggAction *action, + EphyWindow *window) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); @@ -472,9 +405,8 @@ window_cmd_edit_cut (BonoboUIComponent *uic, } void -window_cmd_edit_copy (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_copy (EggAction *action, + EphyWindow *window) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); @@ -494,9 +426,8 @@ window_cmd_edit_copy (BonoboUIComponent *uic, } void -window_cmd_edit_paste (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_paste (EggAction *action, + EphyWindow *window) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); @@ -516,9 +447,8 @@ window_cmd_edit_paste (BonoboUIComponent *uic, } void -window_cmd_edit_select_all (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_select_all (EggAction *action, + EphyWindow *window) { GtkWidget *widget = gtk_window_get_focus (GTK_WINDOW (window)); @@ -538,9 +468,8 @@ window_cmd_edit_select_all (BonoboUIComponent *uic, } void -window_cmd_edit_find_next (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_find_next (EggAction *action, + EphyWindow *window) { EphyDialog *dialog; @@ -552,9 +481,8 @@ window_cmd_edit_find_next (BonoboUIComponent *uic, } void -window_cmd_edit_find_prev (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_find_prev (EggAction *action, + EphyWindow *window) { EphyDialog *dialog; @@ -566,9 +494,20 @@ window_cmd_edit_find_prev (BonoboUIComponent *uic, } void -window_cmd_view_zoom_in (BonoboUIComponent *uic, - EphyWindow *window, - const char *verbname) +window_cmd_view_statusbar (EggAction *action, + EphyWindow *window) +{ +} + +void +window_cmd_view_fullscreen (EggAction *action, + EphyWindow *window) +{ +} + +void +window_cmd_view_zoom_in (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; int zoom; @@ -581,9 +520,8 @@ window_cmd_view_zoom_in (BonoboUIComponent *uic, } void -window_cmd_view_zoom_out (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_view_zoom_out (EggAction *action, + EphyWindow *window) { EphyEmbed *embed; int zoom; @@ -599,17 +537,15 @@ window_cmd_view_zoom_out (BonoboUIComponent *uic, } void -window_cmd_view_zoom_normal (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_view_zoom_normal (EggAction *action, + EphyWindow *window) { ephy_window_set_zoom (window, 100); } void -window_cmd_view_page_source (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_view_page_source (EggAction *action, + EphyWindow *window) { EphyTab *tab; @@ -621,17 +557,15 @@ window_cmd_view_page_source (BonoboUIComponent *uic, } void -window_cmd_tools_history (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_go_history (EggAction *action, + EphyWindow *window) { ephy_window_show_history (window); } void -window_cmd_tools_pdm (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_personal_data (EggAction *action, + EphyWindow *window) { EphyDialog *dialog; @@ -641,9 +575,8 @@ window_cmd_tools_pdm (BonoboUIComponent *uic, } void -window_cmd_edit_prefs (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_prefs (EggAction *action, + EphyWindow *window) { GtkDialog *dialog; @@ -655,101 +588,15 @@ window_cmd_edit_prefs (BonoboUIComponent *uic, gtk_widget_show (GTK_WIDGET(dialog)); } -static void -window_cmd_settings_toolbar_editor_revert_clicked_cb (GtkButton *b, EphyTbEditor *tbe) -{ - gchar *def; - - g_return_if_fail (EPHY_IS_TB_EDITOR (tbe)); - - eel_gconf_unset (CONF_TOOLBAR_SETUP); - def = eel_gconf_get_string (CONF_TOOLBAR_SETUP); - if (def) - { - EphyToolbar *current; - EphyToolbar *avail; - current = ephy_tb_editor_get_toolbar (tbe); - ephy_toolbar_parse (current, def); - g_free (def); - - avail = ephy_tb_editor_get_available (tbe); - g_object_ref (avail); - ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS); - ephy_tb_editor_set_available (tbe, avail); - g_object_unref (avail); - } - -} - -static void -window_cmd_settings_toolbar_editor_current_changed_cb (EphyToolbar *tb, gpointer data) -{ - gchar *current_str; - - g_return_if_fail (EPHY_IS_TOOLBAR (tb)); - - current_str = ephy_toolbar_to_string (tb); - eel_gconf_set_string (CONF_TOOLBAR_SETUP, current_str); - g_free (current_str); -} - void -window_cmd_settings_toolbar_editor (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_edit_toolbar (EggAction *action, + EphyWindow *window) { - static EphyTbEditor *tbe = NULL; - EphyToolbar *avail; - EphyToolbar *current; - gchar *current_str; - GtkButton *revert_button; - - avail = ephy_toolbar_new (); - ephy_toolbar_parse (avail, AVAILABLE_TOOLBAR_ITEMS); - - current_str = eel_gconf_get_string (CONF_TOOLBAR_SETUP); - current = ephy_toolbar_new (); - if (current_str) - { - ephy_toolbar_parse (current, current_str); - g_free (current_str); - } - - if (!tbe) - { - tbe = ephy_tb_editor_new (); - g_object_add_weak_pointer (G_OBJECT (tbe), - (void **)&tbe); - ephy_tb_editor_set_parent (tbe, - GTK_WIDGET(window)); - } - else - { - ephy_tb_editor_show (tbe); - return; - } - - ephy_tb_editor_set_toolbar (tbe, current); - ephy_tb_editor_set_available (tbe, avail); - g_object_unref (avail); - g_object_unref (current); - - g_signal_connect (current, "changed", - G_CALLBACK (window_cmd_settings_toolbar_editor_current_changed_cb), NULL); - - revert_button = ephy_tb_editor_get_revert_button (tbe); - gtk_widget_show (GTK_WIDGET (revert_button)); - - g_signal_connect (revert_button, "clicked", - G_CALLBACK (window_cmd_settings_toolbar_editor_revert_clicked_cb), tbe); - - ephy_tb_editor_show (tbe); } void -window_cmd_help_about (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_help_about (EggAction *action, + EphyWindow *window) { static GtkWidget *about = NULL; @@ -792,23 +639,8 @@ window_cmd_help_about (BonoboUIComponent *uic, } void -window_cmd_set_charset (BonoboUIComponent *uic, - EncodingMenuData *data, - const char* verbname) -{ - EphyWindow *window = data->data; - EphyEmbed *embed; - - embed = ephy_window_get_active_embed (window); - g_return_if_fail (embed != NULL); - - ephy_embed_set_charset (embed, data->encoding); -} - -void -window_cmd_tabs_next (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_tabs_next (EggAction *action, + EphyWindow *window) { GList *tabs; EphyTab *tab; @@ -829,9 +661,8 @@ window_cmd_tabs_next (BonoboUIComponent *uic, } void -window_cmd_tabs_previous (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_tabs_previous (EggAction *action, + EphyWindow *window) { GList *tabs; EphyTab *tab; @@ -852,22 +683,19 @@ window_cmd_tabs_previous (BonoboUIComponent *uic, } void -window_cmd_tabs_move_left (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_tabs_move_left (EggAction *action, + EphyWindow *window) { } -void window_cmd_tabs_move_right (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +void window_cmd_tabs_move_right (EggAction *action, + EphyWindow *window) { } void -window_cmd_tabs_detach (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname) +window_cmd_tabs_detach (EggAction *action, + EphyWindow *window) { EphyTab *tab; GtkWidget *src_page; @@ -886,32 +714,3 @@ window_cmd_tabs_detach (BonoboUIComponent *uic, ephy_tab_set_window (tab, new_win); gtk_widget_show (GTK_WIDGET (new_win)); } - -void -window_cmd_help_manual (BonoboUIComponent *uic, - char *filename, - const char* verbname) -{ - GError *error; - GtkWidget *dialog; - - error = NULL; - gnome_help_display ("Ephy.xml", NULL, &error); - - if (error) - { - dialog = gtk_message_dialog_new (NULL, - GTK_DIALOG_MODAL, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - _("There was an error displaying help: \n%s"), - error->message); - g_signal_connect (G_OBJECT (dialog), "response", - G_CALLBACK (gtk_widget_destroy), - NULL); - - gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - gtk_widget_show (dialog); - g_error_free (error); - } -} diff --git a/src/window-commands.h b/src/window-commands.h index df05a4d50..bf733897c 100644 --- a/src/window-commands.h +++ b/src/window-commands.h @@ -16,181 +16,136 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "egg-action.h" #include "ephy-window.h" #include "ephy-embed-utils.h" -#include <bonobo/bonobo-ui-component.h> +void window_cmd_edit_find (EggAction *action, + EphyWindow *window); -void window_cmd_edit_find (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_print (EggAction *action, + EphyWindow *window); -void window_cmd_file_print (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_stop (EggAction *action, + EphyWindow *window); -void window_cmd_go_stop (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_back (EggAction *action, + EphyWindow *window); -void window_cmd_go_back (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_forward (EggAction *action, + EphyWindow *window); -void window_cmd_go_forward (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_location (EggAction *action, + EphyWindow *window); -void window_cmd_go_go (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_up (EggAction *action, + EphyWindow *window); -void window_cmd_go_up (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_home (EggAction *action, + EphyWindow *window); -void window_cmd_go_home (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_myportal (EggAction *action, + EphyWindow *window); -void window_cmd_go_myportal (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_location (EggAction *action, + EphyWindow *window); -void window_cmd_go_location (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_reload (EggAction *action, + EphyWindow *window); -void window_cmd_go_reload (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_new (EggAction *action, + EphyWindow *window); -void window_cmd_new (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_new_window (EggAction *action, + EphyWindow *window); -void window_cmd_new_window (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_new_tab (EggAction *action, + EphyWindow *window); -void window_cmd_new_tab (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_add_bookmark(EggAction *action, + EphyWindow *window); -void window_cmd_bookmarks_add_default (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_bookmarks (EggAction *action, + EphyWindow *window); -void window_cmd_bookmarks_edit (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_open (EggAction *action, + EphyWindow *window); -void window_cmd_file_open (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_save_as (EggAction *action, + EphyWindow *window); -void window_cmd_file_save_as (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_send_to (EggAction *action, + EphyWindow *window); -void window_cmd_file_send_to (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_close_tab (EggAction *action, + EphyWindow *window); -void window_cmd_file_close_tab (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_file_close_window (EggAction *action, + EphyWindow *window); -void window_cmd_file_close_window (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_edit_cut (EggAction *action, + EphyWindow *window); -void window_cmd_edit_cut (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_edit_copy (EggAction *action, + EphyWindow *window); -void window_cmd_edit_copy (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_edit_paste (EggAction *action, + EphyWindow *window); -void window_cmd_edit_paste (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_edit_select_all (EggAction *action, + EphyWindow *window); -void window_cmd_edit_select_all (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_edit_find_next (EggAction *action, + EphyWindow *window); -void window_cmd_edit_find_next (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_edit_find_prev (EggAction *action, + EphyWindow *window); -void window_cmd_edit_find_prev (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_statusbar (EggAction *action, + EphyWindow *window); -void window_cmd_view_zoom_in (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_fullscreen (EggAction *action, + EphyWindow *window); -void window_cmd_view_zoom_out (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_zoom_in (EggAction *action, + EphyWindow *window); -void window_cmd_view_zoom_normal(BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_zoom_out (EggAction *action, + EphyWindow *window); -void window_cmd_view_page_source(BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_zoom_normal(EggAction *action, + EphyWindow *window); -void window_cmd_tools_history (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_view_page_source(EggAction *action, + EphyWindow *window); -void window_cmd_tools_pdm (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_go_history (EggAction *action, + EphyWindow *window); -void window_cmd_edit_prefs (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); +void window_cmd_edit_personal_data (EggAction *action, + EphyWindow *window); -void -window_cmd_settings_toolbar_editor (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); - -void window_cmd_help_about (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); - -void window_cmd_set_charset (BonoboUIComponent *uic, - EncodingMenuData *data, - const char* verbname); - -void window_cmd_tabs_next (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); - -void window_cmd_tabs_previous (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); - -void window_cmd_tabs_move_left (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); - -void window_cmd_tabs_move_right (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); - -void window_cmd_tabs_detach (BonoboUIComponent *uic, - EphyWindow *window, - const char* verbname); - -void window_cmd_help_manual (BonoboUIComponent *uic, - char *filename, - const char* verbname); +void window_cmd_edit_prefs (EggAction *action, + EphyWindow *window); + +void window_cmd_edit_toolbar (EggAction *action, + EphyWindow *window); + +void window_cmd_help_about (EggAction *action, + EphyWindow *window); + +void window_cmd_tabs_next (EggAction *action, + EphyWindow *window); + +void window_cmd_tabs_previous (EggAction *action, + EphyWindow *window); + +void window_cmd_tabs_move_left (EggAction *action, + EphyWindow *window); + +void window_cmd_tabs_move_right (EggAction *action, + EphyWindow *window); + +void window_cmd_tabs_detach (EggAction *action, + EphyWindow *window); |