summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2009-12-17 23:55:02 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2009-12-17 23:55:02 +0000
commit355799ce0bbb078237dfc1ae9874bbc5342acbc4 (patch)
tree7ca980c01c0d4d1d55a3b7b15418c95c5618afae
parent4346b2b62b940182575e6612e46234355afa083c (diff)
downloadnetsurf-355799ce0bbb078237dfc1ae9874bbc5342acbc4.tar.gz
netsurf-355799ce0bbb078237dfc1ae9874bbc5342acbc4.tar.bz2
Merge branches/MarkieB/gtkmain to trunk.
svn path=/trunk/netsurf/; revision=9729
-rw-r--r--!NetSurf/Resources/SearchEngines20
-rw-r--r--!NetSurf/Resources/de/Messages116
-rw-r--r--!NetSurf/Resources/default.icobin0 -> 1406 bytes
-rw-r--r--!NetSurf/Resources/en/Messages114
-rw-r--r--!NetSurf/Resources/fr/Messages116
-rwxr-xr-x!NetSurf/Resources/it/Messages143
-rw-r--r--!NetSurf/Resources/nl/Messages116
-rw-r--r--Docs/BUILDING-AmigaCross102
-rw-r--r--Docs/Doxyfile2
-rw-r--r--Makefile11
-rw-r--r--Makefile.sources31
-rw-r--r--amiga/download.c2
-rwxr-xr-xamiga/fetch_file.c26
-rwxr-xr-xamiga/gui.c19
-rwxr-xr-xamiga/gui.h2
-rwxr-xr-xamiga/menu.c2
-rwxr-xr-xamiga/save_complete.c843
-rwxr-xr-xamiga/search.c803
-rw-r--r--beos/beos_scaffolding.cpp16
-rw-r--r--beos/beos_search.cpp75
-rw-r--r--content/content.c3
-rw-r--r--content/fetch.c4
-rw-r--r--content/fetch.h18
-rw-r--r--content/fetchcache.c127
-rw-r--r--content/fetchers/fetch_curl.c50
-rw-r--r--content/fetchers/fetch_data.c28
-rw-r--r--desktop/browser.c24
-rw-r--r--desktop/browser.h3
-rw-r--r--desktop/gui.h9
-rw-r--r--desktop/options.c8
-rw-r--r--desktop/options.h2
-rw-r--r--desktop/save_complete.c (renamed from riscos/save_complete.c)236
-rw-r--r--desktop/save_complete.h42
-rw-r--r--desktop/search.c705
-rw-r--r--desktop/search.h91
-rw-r--r--desktop/searchweb.c292
-rw-r--r--desktop/searchweb.h79
-rw-r--r--framebuffer/fb_search.c74
-rw-r--r--gtk/dialogs/gtk_about.c5
-rw-r--r--gtk/dialogs/gtk_options.c244
-rw-r--r--gtk/dialogs/gtk_options.h6
-rw-r--r--gtk/dialogs/gtk_source.c266
-rw-r--r--gtk/gtk_download.c32
-rw-r--r--gtk/gtk_gui.c115
-rw-r--r--gtk/gtk_gui.h14
-rw-r--r--gtk/gtk_history.c18
-rw-r--r--gtk/gtk_login.c2
-rw-r--r--gtk/gtk_menu.c422
-rw-r--r--gtk/gtk_menu.h135
-rw-r--r--gtk/gtk_save.c81
-rw-r--r--gtk/gtk_scaffolding.c2049
-rw-r--r--gtk/gtk_scaffolding.h244
-rw-r--r--gtk/gtk_search.c263
-rw-r--r--gtk/gtk_search.h39
-rw-r--r--gtk/gtk_selection.c5
-rw-r--r--gtk/gtk_tabs.c39
-rw-r--r--gtk/gtk_theme.c773
-rw-r--r--gtk/gtk_theme.h46
-rw-r--r--gtk/gtk_toolbar.c1102
-rw-r--r--gtk/gtk_toolbar.h90
-rw-r--r--gtk/gtk_window.c151
-rw-r--r--gtk/gtk_window.h46
-rw-r--r--gtk/options.h10
-rw-r--r--gtk/res/SearchEngines20
-rw-r--r--gtk/res/default.icobin0 -> 1406 bytes
-rw-r--r--gtk/res/html.pngbin0 -> 3625 bytes
-rw-r--r--gtk/res/login.glade222
-rw-r--r--gtk/res/netsurf.glade1661
-rw-r--r--gtk/res/options.glade772
-rw-r--r--gtk/res/password.glade274
-rw-r--r--gtk/res/ssl.glade197
-rw-r--r--gtk/res/themelist2
-rw-r--r--gtk/res/themes/Alpha.pngbin0 -> 156 bytes
-rw-r--r--gtk/res/themes/gtk+/back.pngbin0 -> 915 bytes
-rw-r--r--gtk/res/themes/gtk+/closetab.pngbin0 -> 1453 bytes
-rw-r--r--gtk/res/themes/gtk+/closewindow.pngbin0 -> 1453 bytes
-rw-r--r--gtk/res/themes/gtk+/copy.pngbin0 -> 697 bytes
-rw-r--r--gtk/res/themes/gtk+/cut.pngbin0 -> 1032 bytes
-rw-r--r--gtk/res/themes/gtk+/delete.pngbin0 -> 1449 bytes
-rw-r--r--gtk/res/themes/gtk+/forward.pngbin0 -> 906 bytes
-rw-r--r--gtk/res/themes/gtk+/fullscreen.pngbin0 -> 606 bytes
-rw-r--r--gtk/res/themes/gtk+/helpabout.pngbin0 -> 982 bytes
-rw-r--r--gtk/res/themes/gtk+/helpcontents.pngbin0 -> 1728 bytes
-rw-r--r--gtk/res/themes/gtk+/history.pngbin0 -> 285 bytes
-rw-r--r--gtk/res/themes/gtk+/home.pngbin0 -> 1050 bytes
-rw-r--r--gtk/res/themes/gtk+/info81
-rw-r--r--gtk/res/themes/gtk+/newtab.pngbin0 -> 736 bytes
-rw-r--r--gtk/res/themes/gtk+/newwindow.pngbin0 -> 736 bytes
-rw-r--r--gtk/res/themes/gtk+/openfile.pngbin0 -> 612 bytes
-rw-r--r--gtk/res/themes/gtk+/paste.pngbin0 -> 893 bytes
-rw-r--r--gtk/res/themes/gtk+/preferences.pngbin0 -> 1691 bytes
-rw-r--r--gtk/res/themes/gtk+/print.pngbin0 -> 818 bytes
-rw-r--r--gtk/res/themes/gtk+/printpreview.pngbin0 -> 1244 bytes
-rw-r--r--gtk/res/themes/gtk+/quit.pngbin0 -> 967 bytes
-rw-r--r--gtk/res/themes/gtk+/reload.pngbin0 -> 1466 bytes
-rw-r--r--gtk/res/themes/gtk+/savepage.pngbin0 -> 1206 bytes
-rw-r--r--gtk/res/themes/gtk+/selectall.pngbin0 -> 717 bytes
-rw-r--r--gtk/res/themes/gtk+/stop.pngbin0 -> 1043 bytes
-rw-r--r--gtk/res/themes/gtk+/viewsource.pngbin0 -> 960 bytes
-rw-r--r--gtk/res/themes/gtk+/zoomminus.pngbin0 -> 941 bytes
-rw-r--r--gtk/res/themes/gtk+/zoomnormal.pngbin0 -> 962 bytes
-rw-r--r--gtk/res/themes/gtk+/zoomplus.pngbin0 -> 993 bytes
-rw-r--r--gtk/res/toolbar.glade126
-rw-r--r--gtk/res/warning.glade79
-rw-r--r--gtk/sexy_icon_entry.c979
-rw-r--r--gtk/sexy_icon_entry.h101
-rw-r--r--image/ico.c12
-rw-r--r--image/ico.h1
-rw-r--r--render/favicon.c232
-rw-r--r--render/favicon.h (renamed from riscos/save_complete.h)17
-rw-r--r--render/html.c8
-rw-r--r--render/html.h3
-rw-r--r--render/html_redraw.c9
-rw-r--r--render/layout.c2
-rw-r--r--render/textplain.c12
-rw-r--r--riscos/gui.c2
-rw-r--r--riscos/gui.h2
-rw-r--r--riscos/menus.c2
-rw-r--r--riscos/save.c67
-rw-r--r--riscos/search.c813
-rw-r--r--riscos/searchweb.c18
-rw-r--r--riscos/window.c15
-rw-r--r--utils/config.h5
-rw-r--r--utils/container.c183
-rw-r--r--utils/container.h3
-rw-r--r--utils/utils.c23
-rw-r--r--utils/utils.h1
127 files changed, 11392 insertions, 5103 deletions
diff --git a/!NetSurf/Resources/SearchEngines b/!NetSurf/Resources/SearchEngines
new file mode 100644
index 000000000..e9eb466c2
--- /dev/null
+++ b/!NetSurf/Resources/SearchEngines
@@ -0,0 +1,20 @@
+Google|www.google.com|http://www.google.com/search?q=%s|http://www.google.com/favicon.ico|
+Yahoo|search.yahoo.com|http://search.yahoo.com/search?p=%s|http://www.yahoo.com/favicon.ico|
+Bing|www.bing.com|http://www.bing.com/search?q=%s|http://www.bing.com/favicon.ico|
+Business.com|www.business.com|http://www.business.com/search/rslt_default.asp?query=%s|http://www.business.com/favicon.ico|
+Omgili|www.omgili.com|http://www.omgili.com/AAAAA/%s.html|http://www.omgili.com/favicon.ico|
+BBC News|search.bbc.co.uk|http://search.bbc.co.uk/search?q=%s&tab=ns|http://news.bbc.co.uk/favicon.ico|
+Ubuntu Packages|packages.ubuntu.com|http://packages.ubuntu.com/search?keywords=%s|http://packages.ubuntu.com/favicon.ico|
+Creative Commons|creativecommons.org|http://creativecommons.org/?s=%s|http://creativecommons.org/favicon.ico|
+Ask.com|www.ask.com|http://www.ask.com/web?q=%s|http://www.ask.com/favicon.ico|
+Answers.com|www.answers.com|http://www.answers.com/%s|http://www.answers.com/favicon.ico|
+Dictionary.com|dictionary.reference.com|http://dictionary.reference.com/browse/%s?jss=0|http://dictionary.reference.com/favicon.ico|
+Youtube|www.youtube.com|http://www.youtube.com/results?search_query=%s|http://www.youtube.com/favicon.ico|
+AeroMp3|www.aeromp3.com|http://www.aeromp3.com/search?q=%s|http://www.aeromp3.com/favicon.ico|
+AOL|search.aol.com|http://search.aol.com/aol/search?query=%s|http://www.aol.com/favicon.ico|
+Baidu|www.baidu.com|http://www.baidu.com/s?wd=%s|http://www.baidu.com/favicon.ico|
+Amazon|www.amazon.com|http://www.amazon.com/s/ref=nb_ss_gw?field-keywords=%s|http://www.amazon.com/favicon.ico|
+Ebay|shop.ebay.com|http://shop.ebay.com/items/%s|http://www.ebay.com/favicon.ico|
+IMDB|www.imdb.com|http://www.imdb.com/find?q=%s|http://www.imdb.com/favicon.ico|
+ESPN|search.espn.go.com|http://search.espn.go.com/%s/|http://www.espn.go.com/favicon.ico|
+Wikipedia|en.wikipedia.org|http://en.wikipedia.org/w/index.php?title=Special%%3ASearch&search=%s|http://en.wikipedia.org/favicon.ico|
diff --git a/!NetSurf/Resources/de/Messages b/!NetSurf/Resources/de/Messages
index 0f4722bab..058273ee7 100644
--- a/!NetSurf/Resources/de/Messages
+++ b/!NetSurf/Resources/de/Messages
@@ -432,10 +432,118 @@ gtkFailed:Download failed
gtkFileError:File error: %s
gtkInfo:%s from %s is %s in size
gtkSave:Save file as...
+gtkSourceSave:Save Source
+gtkPlainSave:Save as text
+gtkFullSave:Save webpage complete - select an empty directory
gtkUnknownHost:an unknown host
gtkUnknownFile:
gtkUnknownSize:unknown
+# gtk Menu / Button labels
+#
+
+gtkNewTab:New _Tab
+gtkNewTabAccel:<ctrl>t
+gtkNewWindow:_New Window
+gtkNewWindowAccel:<ctrl>n
+gtkOpenFile:_Open File
+gtkOpenFileAccel:<ctrl>o
+gtkCloseWindow:_Close Window
+gtkCloseWindowAccel:<ctrl><shift>w
+gtkSavePage:Save Page..
+gtkSavePageAccel:<ctrl>s
+gtkExport:Export
+gtkPlainText:Plain Text..
+gtkDrawFile:Drawfile..
+gtkPostScript:PostScript..
+gtkPDF:PDF..
+gtkPrintPreview:Print Preview..
+gtkPrintPreviewAccel:<ctrl><shift>p
+gtkPrint:Print..
+gtkPrintAccel:<ctrl>p
+gtkQuit:_Quit
+gtkQuitAccel:<ctrl>q
+
+gtkCut:Cu_t
+gtkCutAccel:<ctrl>x
+gtkCopy:_Copy
+gtkCopyAccel:<ctrl>c
+gtkPaste:_Paste
+gtkPasteAccel:<ctrl>v
+gtkDelete:_Delete
+gtkSelectAll:Select _All
+gtkSelectAllAccel:<ctrl>a
+gtkFind:_Find..
+gtkFindAccel:<ctrl>f
+gtkPreferences:P_references
+
+gtkStop:_Stop
+gtkStopAccel:Escape
+gtkReload:_Reload
+gtkReloadAccel:F5
+gtkScaleView:_Scale View
+gtkZoomPlus:Zoom _in
+gtkZoomPlusAccel:<ctrl>plus
+gtkZoomMinus:Zoom _out
+gtkZoomMinusAccel:<ctrl>minus
+gtkZoomNormal:_Normal size
+gtkZoomNormalAccel:<ctrl>0
+gtkFullScreen:_Fullscreen
+gtkFullScreenAccel:F11
+gtkViewSource:View S_ource
+gtkViewSourceAccel:F8
+gtkImages:_Images
+gtkForegroundImages:_Foreground Images
+gtkBackgroundImages:_Background Images
+gtkToolbars:_Toolbars
+gtkMenuBar:_Menu Bar
+gtkToolBar:_Button Bar
+gtkStatusBar:_Status Bar
+gtkDownloads:_Downloads
+gtkDownloadsAccel:<ctrl>d
+gtkSaveWindowSize:S_ave Window Size
+gtkDebugging:De_bugging
+gtkToggleDebugging:T_oggle debug rendering
+gtkSaveBoxTree:_Save box tree
+gtkSaveDomTree:Save DOM tree
+
+gtkBack:_Back
+gtkBackAccel:<alt>Left
+gtkForward:_Forward
+gtkForwardAccel:<alt>Right
+gtkHome:_Home
+gtkHomeAccel:<alt>Down
+gtkLocalHistory:_Local History
+gtkLocalHistoryAccel:<ctrl>h
+gtkGlobalHistory:_Global History
+gtkGlobalHistoryAccel:<ctrl><shift>h
+gtkAddBookMarks:_Add to Bookmarks..
+gtkShowBookMarks:_Show Bookmarks..
+gtkShowBookMarksAccel:F6
+gtkOpenLocation:_Open Location..
+gtkOpenLocationAccel:<ctrl>l
+
+gtkNextTab:_Next tab
+gtkNextTabAccel:<ctrl>Right
+gtkPrevTab:_Previous tab
+gtkPrevTabAccel:<ctrl>Left
+gtkCloseTab:_Close tab
+gtkCloseTabAccel:<ctrl>w
+
+gtkContents:_Contents
+gtkGuide:User _guide
+gtkUserInformation:User _information
+gtkAbout:_About
+
+
+gtkToolBarTitle:Toolbar custom button store
+gtkAddThemeTitle:Select folder containing theme images
+
+gtkThemeFolderInstructions:To Install a theme, create a directory full of appropriately-named images as a subdirectory of gtk/res/themes/
+gtkThemeFolderSub:Select a subdirectory of the themes folder
+gtkThemeDup:Theme is already included
+gtkThemeAdd:Theme added successfully
+
# Printing user interface tokens
# ==============================
#
@@ -459,6 +567,8 @@ Printing:Printing page
NotFound:nichts
Next:Next
Prev:Previous
+ShowAll:Show All
+CaseSens:Case Sensitive
# 401 login user interface tokens
@@ -578,6 +688,9 @@ MiscError:Unerwarteter Fehler:
FileError:Datei existiert nicht:
PrintError:Ein Fehler trat während des Druckens auf:
AWNotSeen:Das Programm AWViewer wurde nicht gefunden.
+EncNotRec:Encoding type not recognised.
+FileOpenError:could not open file '%s'
+DirectoryError:directory '%s' already exists
# Specific errors - displayed in a dialog box
#
@@ -589,11 +702,13 @@ NoDiscSpace:Nicht genug Speicherplatz auf dem Medium vorhanden.
Template:Ein Template für ein Fenster fehlt in der Datei Templates. Bitte NetSurf neu installieren.
HotlistSaveError:Hotlist konnte nicht korrekt gespeichert werden.
HotlistLoadError:Hotlist konnte nicht korrekt geladen werden.
+NoDirError:%s is not a directory
NoPathError:Symbol in ein Verzeichnisfenster ziehen um zu Speichern.
NoNameError:Bitte einen Namen eingeben.
NoURLError:Bitte eine URL Adresse eingeben.
URIError:NetSurf konnte die URI Datei nicht lesen. Syntax Fehler.
EmptyError:Die Datei ist leer.
+SearchError:Invalid Search.
PrintErrorRO2:Der Drucker scheint beschäftigt zu sein.
AWNotSeen:Please locate the AWViewer application and try again.
@@ -636,6 +751,7 @@ Done:Dokument fertiggestellt
BadRedirect:Falsche URL für Redirect
FetchFailed:Kann Dokument nicht fetchen
NotCSS:Warnung: Stylesheet ist kein CSS
+NotFavIco:Favicon not supported
BadObject:Warnung: falscher Objekttyp
ObjError:Fehler beim Laden des Objektes: %s
ParsingFail:Dokumentparsing ist fehlgeschlagen.
diff --git a/!NetSurf/Resources/default.ico b/!NetSurf/Resources/default.ico
new file mode 100644
index 000000000..1cb432828
--- /dev/null
+++ b/!NetSurf/Resources/default.ico
Binary files differ
diff --git a/!NetSurf/Resources/en/Messages b/!NetSurf/Resources/en/Messages
index 55f5b191d..a787eeb3d 100644
--- a/!NetSurf/Resources/en/Messages
+++ b/!NetSurf/Resources/en/Messages
@@ -434,12 +434,119 @@ gtkFileError:File error: %s
gtkInfo:%s from %s is %s in size
gtkSave:Save file as...
gtkSourceSave:Save source
+gtkplainSave:Save plain text
+gtkcompleteSave:Save webpage complete - select an empty directory
gtkSaveConfirm:File saved
gtkSaveCancelled:File not saved
gtkUnknownHost:an unknown host
gtkUnknownFile:
gtkUnknownSize:unknown
+# gtk Menu / Button labels
+#
+
+gtkNewTab:New _Tab
+gtkNewTabAccel:<ctrl>t
+gtkNewWindow:_New Window
+gtkNewWindowAccel:<ctrl>n
+gtkOpenFile:_Open File
+gtkOpenFileAccel:<ctrl>o
+gtkCloseWindow:_Close Window
+gtkCloseWindowAccel:<ctrl><shift>w
+gtkSavePage:Save Page..
+gtkSavePageAccel:<ctrl>s
+gtkExport:Export
+gtkPlainText:Plain Text..
+gtkDrawFile:Drawfile..
+gtkPostScript:PostScript..
+gtkPDF:PDF..
+gtkPrintPreview:Print Preview..
+gtkPrintPreviewAccel:<ctrl><shift>p
+gtkPrint:Print..
+gtkPrintAccel:<ctrl>p
+gtkQuitMenu:_Quit
+gtkQuitMenuAccel:<ctrl>q
+
+gtkCut:Cu_t
+gtkCutAccel:<ctrl>x
+gtkCopy:_Copy
+gtkCopyAccel:<ctrl>c
+gtkPaste:_Paste
+gtkPasteAccel:<ctrl>v
+gtkDelete:_Delete
+gtkSelectAll:Select _All
+gtkSelectAllAccel:<ctrl>a
+gtkFind:_Find..
+gtkFindAccel:<ctrl>f
+gtkPreferences:P_references
+
+gtkStop:_Stop
+gtkStopAccel:Escape
+gtkReload:_Reload
+gtkReloadAccel:F5
+gtkScaleView:_Scale View
+gtkZoomPlus:Zoom _in
+gtkZoomPlusAccel:<ctrl>plus
+gtkZoomMinus:Zoom _out
+gtkZoomMinusAccel:<ctrl>minus
+gtkZoomNormal:_Normal size
+gtkZoomNormalAccel:<ctrl>0
+gtkFullScreen:_Fullscreen
+gtkFullScreenAccel:F11
+gtkViewSource:View S_ource
+gtkViewSourceAccel:F8
+gtkImages:_Images
+gtkForegroundImages:_Foreground Images
+gtkBackgroundImages:_Background Images
+gtkToolbars:_Toolbars
+gtkMenuBar:_Menu Bar
+gtkToolBar:_Button Bar
+gtkStatusBar:_Status Bar
+gtkDownloads:_Downloads
+gtkDownloadsAccel:<ctrl>d
+gtkSaveWindowSize:S_ave Window Size
+gtkDebugging:De_bugging
+gtkToggleDebugging:T_oggle debug rendering
+gtkSaveBoxTree:_Save box tree
+gtkSaveDomTree:Save DOM tree
+
+gtkBack:_Back
+gtkBackAccel:<alt>Left
+gtkForward:_Forward
+gtkForwardAccel:<alt>Right
+gtkHome:_Home
+gtkHomeAccel:<alt>Down
+gtkLocalHistory:_Local History
+gtkLocalHistoryAccel:<ctrl>h
+gtkGlobalHistory:_Global History
+gtkGlobalHistoryAccel:<ctrl><shift>h
+gtkAddBookMarks:_Add to Bookmarks..
+gtkShowBookMarks:_Show Bookmarks..
+gtkShowBookMarksAccel:F6
+gtkOpenLocation:_Open Location..
+gtkOpenLocationAccel:<ctrl>l
+
+gtkNextTab:_Next tab
+gtkNextTabAccel:<ctrl>Right
+gtkPrevTab:_Previous tab
+gtkPrevTabAccel:<ctrl>Left
+gtkCloseTab:_Close tab
+gtkCloseTabAccel:<ctrl>w
+
+gtkContents:_Contents
+gtkGuide:User _guide
+gtkUserInformation:User _information
+gtkAbout:_About
+
+
+gtkToolBarTitle:Toolbar custom button store
+gtkAddThemeTitle:Select folder containing theme images
+
+gtkThemeFolderInstructions:To Install a theme, create a directory full of appropriately-named images as a subdirectory of gtk/res/themes/
+gtkThemeFolderSub:Select a subdirectory of the themes folder
+gtkThemeDup:Theme is already included
+gtkThemeAdd:Theme added successfully
+
# Printing user interface tokens
# ==============================
#
@@ -463,6 +570,8 @@ Printing:Printing page
NotFound:Not found
Next:Next
Prev:Previous
+ShowAll:Show All
+CaseSens:Case Sensitive
# 401 login user interface tokens
@@ -593,14 +702,18 @@ NoDiscSpace:Not enough space available on disc.
Template:A window template is missing from the Templates file. Please reinstall NetSurf.
HotlistSaveError:The hotlist was unable to be correctly saved.
HotlistLoadError:The hotlist was unable to be correctly loaded.
+NoDirError:%s is not a directory
NoPathError:To save, drag the icon to a directory display
NoNameError:Please enter a name
NoURLError:Please enter a URL
URIError:NetSurf was unable to parse this URI file due to a syntax error.
EmptyError:file is empty.
+SearchError:Invalid Search.
PrintErrorRO2:It appears that the printer is busy.
AWNotSeen:Please locate the AWViewer application and try again.
EncNotRec:Encoding type not recognised.
+FileOpenError:could not open file '%s'
+DirectoryError:directory '%s' already exists
# Error messages for Amiga version only
CompError:Unable to open
@@ -641,6 +754,7 @@ Done:Document done
BadRedirect:Bad redirect URL
FetchFailed:Unable to fetch document
NotCSS:Warning: stylesheet is not CSS
+NotFavIco:Favicon not supported
BadObject:Warning: bad object type
ObjError:Error loading object: %s
ParsingFail:Parsing the document failed.
diff --git a/!NetSurf/Resources/fr/Messages b/!NetSurf/Resources/fr/Messages
index 6d8fe304c..c0fc0af5e 100644
--- a/!NetSurf/Resources/fr/Messages
+++ b/!NetSurf/Resources/fr/Messages
@@ -432,10 +432,118 @@ gtkFailed:Download failed
gtkFileError:File error: %s
gtkInfo:%s from %s is %s in size
gtkSave:Save file as...
+gtkSourceSave:Save Source
+gtkPlainSave:Save as text
+gtkFullSave:Save webpage complete - select an empty directory
gtkUnknownHost:an unknown host
gtkUnknownFile:
gtkUnknownSize:unknown
+# gtk Menu / Button labels
+#
+
+gtkNewTab:New _Tab
+gtkNewTabAccel:<ctrl>t
+gtkNewWindow:_New Window
+gtkNewWindowAccel:<ctrl>n
+gtkOpenFile:_Open File
+gtkOpenFileAccel:<ctrl>o
+gtkCloseWindow:_Close Window
+gtkCloseWindowAccel:<ctrl><shift>w
+gtkSavePage:Save Page..
+gtkSavePageAccel:<ctrl>s
+gtkExport:Export
+gtkPlainText:Plain Text..
+gtkDrawFile:Drawfile..
+gtkPostScript:PostScript..
+gtkPDF:PDF..
+gtkPrintPreview:Print Preview..
+gtkPrintPreviewAccel:<ctrl><shift>p
+gtkPrint:Print..
+gtkPrintAccel:<ctrl>p
+gtkQuit:_Quit
+gtkQuitAccel:<ctrl>q
+
+gtkCut:Cu_t
+gtkCutAccel:<ctrl>x
+gtkCopy:_Copy
+gtkCopyAccel:<ctrl>c
+gtkPaste:_Paste
+gtkPasteAccel:<ctrl>v
+gtkDelete:_Delete
+gtkSelectAll:Select _All
+gtkSelectAllAccel:<ctrl>a
+gtkFind:_Find..
+gtkFindAccel:<ctrl>f
+gtkPreferences:P_references
+
+gtkStop:_Stop
+gtkStopAccel:Escape
+gtkReload:_Reload
+gtkReloadAccel:F5
+gtkScaleView:_Scale View
+gtkZoomPlus:Zoom _in
+gtkZoomPlusAccel:<ctrl>plus
+gtkZoomMinus:Zoom _out
+gtkZoomMinusAccel:<ctrl>minus
+gtkZoomNormal:_Normal size
+gtkZoomNormalAccel:<ctrl>0
+gtkFullScreen:_Fullscreen
+gtkFullScreenAccel:F11
+gtkViewSource:View S_ource
+gtkViewSourceAccel:F8
+gtkImages:_Images
+gtkForegroundImages:_Foreground Images
+gtkBackgroundImages:_Background Images
+gtkToolbars:_Toolbars
+gtkMenuBar:_Menu Bar
+gtkToolBar:_Button Bar
+gtkStatusBar:_Status Bar
+gtkDownloads:_Downloads
+gtkDownloadsAccel:<ctrl>d
+gtkSaveWindowSize:S_ave Window Size
+gtkDebugging:De_bugging
+gtkToggleDebugging:T_oggle debug rendering
+gtkSaveBoxTree:_Save box tree
+gtkSaveDomTree:Save DOM tree
+
+gtkBack:_Back
+gtkBackAccel:<alt>Left
+gtkForward:_Forward
+gtkForwardAccel:<alt>Right
+gtkHome:_Home
+gtkHomeAccel:<alt>Down
+gtkLocalHistory:_Local History
+gtkLocalHistoryAccel:<ctrl>h
+gtkGlobalHistory:_Global History
+gtkGlobalHistoryAccel:<ctrl><shift>h
+gtkAddBookMarks:_Add to Bookmarks..
+gtkShowBookMarks:_Show Bookmarks..
+gtkShowBookMarksAccel:F6
+gtkOpenLocation:_Open Location..
+gtkOpenLocationAccel:<ctrl>l
+
+gtkNextTab:_Next tab
+gtkNextTabAccel:<ctrl>Right
+gtkPrevTab:_Previous tab
+gtkPrevTabAccel:<ctrl>Left
+gtkCloseTab:_Close tab
+gtkCloseTabAccel:<ctrl>w
+
+gtkContents:_Contents
+gtkGuide:User _guide
+gtkUserInformation:User _information
+gtkAbout:_About
+
+
+gtkToolBarTitle:Toolbar custom button store
+gtkAddThemeTitle:Select folder containing theme images
+
+gtkThemeFolderInstructions:To Install a theme, create a directory full of appropriately-named images as a subdirectory of gtk/res/themes/
+gtkThemeFolderSub:Select a subdirectory of the themes folder
+gtkThemeDup:Theme is already included
+gtkThemeAdd:Theme added successfully
+
# Printing user interface tokens
# ==============================
#
@@ -459,6 +567,8 @@ Printing:Printing page
NotFound:Non trouvé
Next:Next
Prev:Previous
+ShowAll:Show All
+CaseSens:Case Sensitive
# 401 login user interface tokens
@@ -578,6 +688,9 @@ MiscError:Une erreur inattendue s'est produite:
FileError:Le fichier n'existe pas:
PrintError:Une erreur s'est produite lors de l'impression:
AWNotSeen:Localisez l'application AMViewer SVP puis réessayez.
+EncNotRec:Encoding type not recognised.
+FileOpenError:could not open file '%s'
+DirectoryError:directory '%s' already exists
# Specific errors - displayed in a dialog box
#
@@ -589,11 +702,13 @@ NoDiscSpace:Pas assez d'espace disque disponible.
Template:Un modèle de fenêtre est absent du fichier Templates. Réinstallez NetSurf SVP.
HotlistSaveError:Les favoris n'ont pas pu être sauvés correctement.
HotlistLoadError:Les favoris n'ont pas pu être chargés correctement.
+NoDirError:%s n'est pas un répertoire
NoPathError:Pour sauver, lâcher cette icône dans une fenêtre de Filer
NoNameError:Entrez un nom SVP
NoURLError:Entrez une URL SVP
URIError:NetSurf est incapable de traiter ce fichier URI à cause d'une erreur de syntaxe.
EmptyError:Le fichier est vide.
+SearchError:Recherche Non-Valide.
PrintErrorRO2:Il semble que l'imprimante soit occupée.
AWNotSeen:Localisez l'application AMViewer SVP puis réessayez.
@@ -636,6 +751,7 @@ Done:Document terminé
BadRedirect:Mauvais URL de redirection
FetchFailed:Récupération du fichier impossible
NotCSS:Attention: feuille de style non CSS
+NotFavIco:Favicon non-soutenu
BadObject:Attention: mauvais type d'objet
ObjError:Erreur lors du chargement de: %s
ParsingFail:L'analyse syntaxique du document a échoué.
diff --git a/!NetSurf/Resources/it/Messages b/!NetSurf/Resources/it/Messages
index 86953b34f..e824fbbe7 100755
--- a/!NetSurf/Resources/it/Messages
+++ b/!NetSurf/Resources/it/Messages
@@ -214,7 +214,7 @@ URLSuggest:URL Recenti
Languages:Lingua
#
# Network pane
-ProxyType:Tipo di proxy
+ProxyType:Tipo di Proxy
ProxyNone:Nessun proxy
ProxyNoAuth:Proxy semplice
ProxyBasic:Autentificazione di Base
@@ -437,12 +437,119 @@ gtkFileError:Errore File: %s
gtkInfo:%s da %s è %s come dimensione
gtkSave:Salva file come...
gtkSourceSave:Salva sorgente
+gtkPlainSave:Save as text
+gtkFullSave:Save webpage complete - select an empty directory
gtkSaveConfirm:File salvato
gtkSaveCancelled:File non salvato
gtkUnknownHost:un Host sconosciuto
gtkUnknownFile:
gtkUnknownSize:sconosciuto
+# gtk Menu / Button labels
+#
+
+gtkNewTab:New _Tab
+gtkNewTabAccel:<ctrl>t
+gtkNewWindow:_New Window
+gtkNewWindowAccel:<ctrl>n
+gtkOpenFile:_Open File
+gtkOpenFileAccel:<ctrl>o
+gtkCloseWindow:_Close Window
+gtkCloseWindowAccel:<ctrl><shift>w
+gtkSavePage:Save Page..
+gtkSavePageAccel:<ctrl>s
+gtkExport:Export
+gtkPlainText:Plain Text..
+gtkDrawFile:Drawfile..
+gtkPostScript:PostScript..
+gtkPDF:PDF..
+gtkPrintPreview:Print Preview..
+gtkPrintPreviewAccel:<ctrl><shift>p
+gtkPrint:Print..
+gtkPrintAccel:<ctrl>p
+gtkQuit:_Quit
+gtkQuitAccel:<ctrl>q
+
+gtkCut:Cu_t
+gtkCutAccel:<ctrl>x
+gtkCopy:_Copy
+gtkCopyAccel:<ctrl>c
+gtkPaste:_Paste
+gtkPasteAccel:<ctrl>v
+gtkDelete:_Delete
+gtkSelectAll:Select _All
+gtkSelectAllAccel:<ctrl>a
+gtkFind:_Find..
+gtkFindAccel:<ctrl>f
+gtkPreferences:P_references
+
+gtkStop:_Stop
+gtkStopAccel:Escape
+gtkReload:_Reload
+gtkReloadAccel:F5
+gtkScaleView:_Scale View
+gtkZoomPlus:Zoom _in
+gtkZoomPlusAccel:<ctrl>plus
+gtkZoomMinus:Zoom _out
+gtkZoomMinusAccel:<ctrl>minus
+gtkZoomNormal:_Normal size
+gtkZoomNormalAccel:<ctrl>0
+gtkFullScreen:_Fullscreen
+gtkFullScreenAccel:F11
+gtkViewSource:View S_ource
+gtkViewSourceAccel:F8
+gtkImages:_Images
+gtkForegroundImages:_Foreground Images
+gtkBackgroundImages:_Background Images
+gtkToolbars:_Toolbars
+gtkMenuBar:_Menu Bar
+gtkToolBar:_Button Bar
+gtkStatusBar:_Status Bar
+gtkDownloads:_Downloads
+gtkDownloadsAccel:<ctrl>d
+gtkSaveWindowSize:S_ave Window Size
+gtkDebugging:De_bugging
+gtkToggleDebugging:T_oggle debug rendering
+gtkSaveBoxTree:_Save box tree
+gtkSaveDomTree:Save DOM tree
+
+gtkBack:_Back
+gtkBackAccel:<alt>Left
+gtkForward:_Forward
+gtkForwardAccel:<alt>Right
+gtkHome:_Home
+gtkHomeAccel:<alt>Down
+gtkLocalHistory:_Local History
+gtkLocalHistoryAccel:<ctrl>h
+gtkGlobalHistory:_Global History
+gtkGlobalHistoryAccel:<ctrl><shift>h
+gtkAddBookMarks:_Add to Bookmarks..
+gtkShowBookMarks:_Show Bookmarks..
+gtkShowBookMarksAccel:F6
+gtkOpenLocation:_Open Location..
+gtkOpenLocationAccel:<ctrl>l
+
+gtkNextTab:_Next tab
+gtkNextTabAccel:<ctrl>Right
+gtkPrevTab:_Previous tab
+gtkPrevTabAccel:<ctrl>Left
+gtkCloseTab:_Close tab
+gtkCloseTabAccel:<ctrl>w
+
+gtkContents:_Contents
+gtkGuide:User _guide
+gtkUserInformation:User _information
+gtkAbout:_About
+
+
+gtkToolBarTitle:Toolbar custom button store
+gtkAddThemeTitle:Select folder containing theme images
+
+gtkThemeFolderInstructions:To Install a theme, create a directory full of appropriately-named images as a subdirectory of gtk/res/themes/
+gtkThemeFolderSub:Select a subdirectory of the themes folder
+gtkThemeDup:Theme is already included
+gtkThemeAdd:Theme added successfully
+
# Printing user interface tokens
# ==============================
#
@@ -466,6 +573,8 @@ Printing:Stampa della pagina
NotFound:Non trovato
Next:Successivo
Prev:Precedente
+ShowAll:Show All
+CaseSens:Case Sensitive
# 401 login user interface tokens
# ===============================
@@ -487,17 +596,17 @@ Cancel:Annulla
# This section contains tokens which are used in the
# SSL certificate verification dialog box.
#
-SSLCerts:Certificati SSL
-SSLError:NetSurf non è stato in grado di verificare l'autenticità del certificato SSL. Per favore verifica i dettagli qui sotto elencati.
-Subject:Oggetto
-Issuer:Depositario
-Version:Versione
-ValidFrom:Valido da
-ValidTo:Valido fino
-Type:Tipo
-Serial:Seriale
-Accept:Accetta
-Reject:Rifiuta
+SSLCerts:SSL certificates
+SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
+Subject:Subject
+Issuer:Issuer
+Version:Version
+ValidFrom:Valid from
+ValidTo:Valid until
+Type:Type
+Serial:Serial
+Accept:Accept
+Reject:Reject
# Content
@@ -584,6 +693,9 @@ MiscError:Si è verificato un errore inatteso:
FileError:Il file è inesistente:
PrintError:Si è verificato un errore durante la stampa:
AWNotSeen:Per favore imposta l'applicazione AWViewer e riprova ancora.
+EncNotRec:Encoding type not recognised.
+FileOpenError:could not open file '%s'
+DirectoryError:directory '%s' already exists
# Specific errors - displayed in a dialog box
#
@@ -595,10 +707,12 @@ NoDiscSpace:Spazio insufficiente nel disco.
Template:Una finestra di template risulta mancante. Per favore reinstalla NetSurf.
HotlistSaveError:Non è stato possibile salvare correttamente i segnalibri.
HotlistLoadError:Non è stato possibile caricare correttamente i segnalibri.
+NoDirError:%s is not a directory
NoPathError:Per salvare, trascinare l'icona in una directory di visualizzazione.
NoNameError:Inserisci un nome
NoURLError:Inserisci un URL
URIError:NetSurf non è stato in grado di processare questo file URI a causa di un errore di sintassi.
+SearchError:Invalid Search.
EmptyError:Il file è vuoto.
PrintErrorRO2:Sembra che la stampante sia occupata.
AWNotSeen:Per favore imposta l'applicazione AWViewer e riprova ancora.
@@ -642,7 +756,8 @@ Done:Documento completato
#
BadRedirect:Errata redirezione dell'URL
FetchFailed:Impossibile ottenere il documento
-NotCSS:Attenzione: la dicitura "Foglio di stile" non ha nulla a che vedere con i CSS
+NotCSS:Attenzione: "Foglio di stile" non ha nulla a che spartire con i CSS
+NotFavIco:Favicon not supported
BadObject:Attenzione: errato tipo di oggetto
ObjError:Errore di caricamento dell'oggetto: %s
ParsingFail:Analisi del documento fallita.
@@ -678,7 +793,7 @@ HTTP404:Non trovato
HTTP405:Metodo non permesso
HTTP406:Non accettabile
HTTP407:Autentificazione Proxy necessaria
-HTTP408:Messaggio di TimeOut
+HTTP408:Richiesta TimeOut
HTTP409:Conflitto
HTTP410:Irraggiungibile
HTTP411:Lunghezza richiesta
diff --git a/!NetSurf/Resources/nl/Messages b/!NetSurf/Resources/nl/Messages
index 3c28db983..3916340d6 100644
--- a/!NetSurf/Resources/nl/Messages
+++ b/!NetSurf/Resources/nl/Messages
@@ -432,10 +432,118 @@ gtkFailed:Download failed
gtkFileError:File error: %s
gtkInfo:%s from %s is %s in size
gtkSave:Save file as...
+gtkSourceSave:Save Source
+gtkPlainSave:Save as text
+gtkFullSave:Save webpage complete - select an empty directory
gtkUnknownHost:an unknown host
gtkUnknownFile:
gtkUnknownSize:unknown
+# gtk Menu / Button labels
+#
+
+gtkNewTab:New _Tab
+gtkNewTabAccel:<ctrl>t
+gtkNewWindow:_New Window
+gtkNewWindowAccel:<ctrl>n
+gtkOpenFile:_Open File
+gtkOpenFileAccel:<ctrl>o
+gtkCloseWindow:_Close Window
+gtkCloseWindowAccel:<ctrl><shift>w
+gtkSavePage:Save Page..
+gtkSavePageAccel:<ctrl>s
+gtkExport:Export
+gtkPlainText:Plain Text..
+gtkDrawFile:Drawfile..
+gtkPostScript:PostScript..
+gtkPDF:PDF..
+gtkPrintPreview:Print Preview..
+gtkPrintPreviewAccel:<ctrl><shift>p
+gtkPrint:Print..
+gtkPrintAccel:<ctrl>p
+gtkQuit:_Quit
+gtkQuitAccel:<ctrl>q
+
+gtkCut:Cu_t
+gtkCutAccel:<ctrl>x
+gtkCopy:_Copy
+gtkCopyAccel:<ctrl>c
+gtkPaste:_Paste
+gtkPasteAccel:<ctrl>v
+gtkDelete:_Delete
+gtkSelectAll:Select _All
+gtkSelectAllAccel:<ctrl>a
+gtkFind:_Find..
+gtkFindAccel:<ctrl>f
+gtkPreferences:P_references
+
+gtkStop:_Stop
+gtkStopAccel:Escape
+gtkReload:_Reload
+gtkReloadAccel:F5
+gtkScaleView:_Scale View
+gtkZoomPlus:Zoom _in
+gtkZoomPlusAccel:<ctrl>plus
+gtkZoomMinus:Zoom _out
+gtkZoomMinusAccel:<ctrl>minus
+gtkZoomNormal:_Normal size
+gtkZoomNormalAccel:<ctrl>0
+gtkFullScreen:_Fullscreen
+gtkFullScreenAccel:F11
+gtkViewSource:View S_ource
+gtkViewSourceAccel:F8
+gtkImages:_Images
+gtkForegroundImages:_Foreground Images
+gtkBackgroundImages:_Background Images
+gtkToolbars:_Toolbars
+gtkMenuBar:_Menu Bar
+gtkToolBar:_Button Bar
+gtkStatusBar:_Status Bar
+gtkDownloads:_Downloads
+gtkDownloadsAccel:<ctrl>d
+gtkSaveWindowSize:S_ave Window Size
+gtkDebugging:De_bugging
+gtkToggleDebugging:T_oggle debug rendering
+gtkSaveBoxTree:_Save box tree
+gtkSaveDomTree:Save DOM tree
+
+gtkBack:_Back
+gtkBackAccel:<alt>Left
+gtkForward:_Forward
+gtkForwardAccel:<alt>Right
+gtkHome:_Home
+gtkHomeAccel:<alt>Down
+gtkLocalHistory:_Local History
+gtkLocalHistoryAccel:<ctrl>h
+gtkGlobalHistory:_Global History
+gtkGlobalHistoryAccel:<ctrl><shift>h
+gtkAddBookMarks:_Add to Bookmarks..
+gtkShowBookMarks:_Show Bookmarks..
+gtkShowBookMarksAccel:F6
+gtkOpenLocation:_Open Location..
+gtkOpenLocationAccel:<ctrl>l
+
+gtkNextTab:_Next tab
+gtkNextTabAccel:<ctrl>Right
+gtkPrevTab:_Previous tab
+gtkPrevTabAccel:<ctrl>Left
+gtkCloseTab:_Close tab
+gtkCloseTabAccel:<ctrl>w
+
+gtkContents:_Contents
+gtkGuide:User _guide
+gtkUserInformation:User _information
+gtkAbout:_About
+
+
+gtkToolBarTitle:Toolbar custom button store
+gtkAddThemeTitle:Select folder containing theme images
+
+gtkThemeFolderInstructions:To Install a theme, create a directory full of appropriately-named images as a subdirectory of gtk/res/themes/
+gtkThemeFolderSub:Select a subdirectory of the themes folder
+gtkThemeDup:Theme is already included
+gtkThemeAdd:Theme added successfully
+
# Printing user interface tokens
# ==============================
#
@@ -459,6 +567,8 @@ Printing:Printing page
NotFound:Niet gevonden
Next:Next
Prev:Previous
+ShowAll:Show All
+CaseSens:Case Sensitive
# 401 login user interface tokens
@@ -578,6 +688,9 @@ MiscError:Er trad een onverwachtte fout op:
FileError:Bestand bestaat niet:
PrintError:Fout tijdens printen:
AWNotSeen:Zoek eerst de AWViewer applicatie en probeer het dan nog eens.
+EncNotRec:Encoding type not recognised.
+FileOpenError:could not open file '%s'
+DirectoryError:directory '%s' already exists
# Specific errors - displayed in a dialog box
#
@@ -589,10 +702,12 @@ NoDiscSpace:Niet genoeg ruimte beschikbaar op disk.
Template:Er ontbreekt een venster sjabloon in het Templates bestand. Installeer NetSurf opnieuw.
HotlistSaveError:The hotlist was unable to be correctly saved.
HotlistLoadError:The hotlist was unable to be correctly loaded.
+NoDirError:%s is not a directory
NoPathError:Sleep het icoon naar een bestandsvenster om het op te slaan.
NoNameError:Geef een naam op
NoURLError:Geef een URL op
URIError:NetSurf was unable to parse this URI file due to a syntax error.
+SearchError:Invalid Search.
EmptyError:bestand is leeg.
PrintErrorRO2:De printer lijkt al bezig te zijn.
AWNotSeen:Please locate the AWViewer application and try again.
@@ -636,6 +751,7 @@ Done:klaar
BadRedirect:foutief doorverwijzen naar URL
FetchFailed:kan dit document niet ophalen
NotCSS:melding: stylesheet is geen CSS
+NotFavIco:Favicon not supported
BadObject:melding: fout object type
ObjError:fout bij laden object: %s
ParsingFail:fout bij ontleden van dit document.
diff --git a/Docs/BUILDING-AmigaCross b/Docs/BUILDING-AmigaCross
new file mode 100644
index 000000000..fcd0889c1
--- /dev/null
+++ b/Docs/BUILDING-AmigaCross
@@ -0,0 +1,102 @@
+to install an Amiga cross-compiler in a Linux distribution, there are instructions at
+
+http://utilitybase.com/article/show/2007/06/23/231/Installing+an+AmigaOS+4+cross+compiler
+
+a more Mac-oriented article [though of potentially general utility] is at
+http://utilitybase.com/article/show/2006/05/21/188/Building+Amiga+OS+4+GCC+Cross+Compiler+for+UNIX%252FMAC
+
+more background at
+http://cross.zerohero.se/os4.html
+
+cross-compile additional libs/tools
+SDK
+http://www.hyperion-entertainment.biz/
+
+newlib
+http://sources.redhat.com/newlib/
+
+clib2
+http://sourceforge.net/projects/clib2/
+
+ixemul
+http://strohmayer.org/sfs/
+
+libnix
+http://sourceforge.net/projects/libnix/
+
+though newlib / clib2 are apparently already included in the ppc-amigaos-gcc tarball
+
+lha utility is debian package lha
+
+then install linked libs in the correct place
+
+[normally /usr/local/amiga]
+so
+sudo chmod --recursive 775 /usr/local/amiga
+sudo chmod --recursive +s /usr/local/amiga
+sudo chown --recursive `whoami` /usr/local/amiga
+sudo chgrp --recursive root /usr/local/amiga
+[mkdir /usr/local/amiga/include]
+
+[may need to set ppc-amigaos-gcc libpaths]
+
+zlib
+download tarball from project homepage, untar in a storage directory /
+download source from your distribution's repository [zlib1g in Ubuntu]
+[cd to top-level directory of zlib containing configure script]
+CC=ppc-amigaos-gcc AR=ppc-amigaos-ar RANLIB=ppc-amigaos-ranlib \
+CFLAGS="-DNO_FSEEKO" ./configure --prefix=/usr/local/amiga
+make
+make install
+
+libxml
+download the tarball from the project's homepage, untar in a storage directory /
+download source from your distribution's repository
+download the tarball from the project's homepage, untar in a storage directory /
+download source from your distribution's repository
+cd into the directory containing the configure file
+$ ./configure --prefix=/usr/local/amiga --host=ppc-amigaos
+$ make
+[need glob.h / change logic in runtest.c]
+$ make install
+
+alternative
+http://www.aminet.net/dev/lib/libxml.lha
+
+
+regex [pre-compiled]
+http://aminet.net/dev/lib/libregex-4.4.3.lha
+
+libcurl
+download the tarball from the project's homepage, untar in a storage directory /
+download source from your distribution's repository
+cd into the directory containing the configure file
+./configure --prefix=/usr/local/amiga --host=ppc-amigaos
+$ make
+[you MUST have either POSIX or glibc strerror_r if strerror_r is found]
+$ make install
+
+alternative
+http://www.aminet.net/dev/lib/libcurl.lha
+
+libiconv [unnecessary as a non-overridable limited version is included in newlib]
+
+openssl
+
+libpng
+
+libmng
+http://www.aminet.net/dev/lib/libmng_so.lha
+http://www.aminet.net/dev/lib/libmng.lha
+
+liblcms
+http://www.aminet.net/dev/lib/liblcms_so.lha
+http://www.aminet.net/dev/lib/liblcms_so.lha
+
+libjpeg
+
+libparserutils
+libhubbub
+libcss
+libnsbmp
+libnsgif
diff --git a/Docs/Doxyfile b/Docs/Doxyfile
index d928c5e0b..862566959 100644
--- a/Docs/Doxyfile
+++ b/Docs/Doxyfile
@@ -896,6 +896,8 @@ INCLUDE_FILE_PATTERNS =
PREDEFINED = riscos CSS_INTERNALS WITH_ARTWORKS WITH_BMP WITH_DRAW WITH_DRAW_EXPORT WITH_GIF WITH_JPEG WITH_MMAP WITH_MNG WITH_NSSPRITE WITH_NS_SVG WITH_PLUGIN WITH_RSVG WITH_SAVE_COMPLETE WITH_SPRITE WITH_THEME_INSTALL WITH_PDF_EXPORT
+PREDEFINED = gtk WITH_THEME_INSTALL
+
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded.
# The macro definition that is found in the sources will be used.
diff --git a/Makefile b/Makefile
index 22d694257..faedb5127 100644
--- a/Makefile
+++ b/Makefile
@@ -109,6 +109,11 @@ STRIP=strip
# Override this only if the host compiler is called something different
HOST_CC := gcc
+ifeq ($(TARGET),amiga)
+ ifneq ($(HOST),amiga)
+ CC := ppc-amigaos-gcc
+ endif
+endif
ifeq ($(TARGET),riscos)
ifeq ($(HOST),riscos)
@@ -550,6 +555,9 @@ else
$(Q)$(ELF2AIF) $(EXETARGET:,ff8=,e1f) $(EXETARGET)
$(Q)$(RM) $(EXETARGET:,ff8=,e1f)
endif
+ifeq ($(TARGET),gtk)
+ $(Q)$(TOUCH) gtk/res/toolbarIndices
+endif
ifeq ($(NETSURF_STRIP_BINARY),YES)
$(VQ)echo " STRIP: $(EXETARGET)"
$(Q)$(STRIP) $(EXETARGET)
@@ -749,10 +757,13 @@ install-gtk: nsgtk
@cp -vRL gtk/res/Aliases $(DESTDIR)$(NETSURF_GTK_RESOURCES)
@cp -vrL gtk/res/docs $(DESTDIR)/$(NETSURF_GTK_RESOURCES)
gzip -9v < gtk/res/messages > $(DESTDIR)$(NETSURF_GTK_RESOURCES)messages
+ gzip -9v < gtk/res/SearchEngines > $(DESTDIR)$(NETSURF_GTK_RESOURCES)SearchEngines
gzip -9v < gtk/res/downloads.glade > $(DESTDIR)$(NETSURF_GTK_RESOURCES)downloads.glade
gzip -9v < gtk/res/netsurf.glade > $(DESTDIR)$(NETSURF_GTK_RESOURCES)netsurf.glade
gzip -9v < gtk/res/options.glade > $(DESTDIR)$(NETSURF_GTK_RESOURCES)options.glade
gzip -9v < gtk/res/history.glade > $(DESTDIR)$(NETSURF_GTK_RESOURCES)history.glade
+ gzip -9v < gtk/res/toolbar.glade >
+ $(DESTDIR)$(NETSURF_GTK_RESOURCES)toolbar.glade
gzip -9v < gtk/res/source.glade > $(DESTDIR)$(NETSURF_GTK_RESOURCES)source.glade
install-beos: NetSurf
diff --git a/Makefile.sources b/Makefile.sources
index 938b82716..2a4721850 100644
--- a/Makefile.sources
+++ b/Makefile.sources
@@ -8,13 +8,13 @@
S_CONTENT := content.c fetch.c fetchcache.c urldb.c \
fetchers/fetch_curl.c fetchers/fetch_data.c
S_CSS := css.c dump.c internal.c select.c utils.c
-S_RENDER := box.c box_construct.c box_normalise.c directory.c \
+S_RENDER := box.c box_construct.c box_normalise.c directory.c favicon.c \
font.c form.c html.c html_redraw.c hubbub_binding.c imagemap.c \
layout.c list.c table.c textplain.c
-S_UTILS := base64.c filename.c hashtable.c locale.c messages.c talloc.c \
- url.c utf8.c utils.c useragent.c
-S_DESKTOP := knockout.c options.c print.c tree.c version.c textarea.c \
- plot_style.c scroll.c
+S_UTILS := base64.c filename.c hashtable.c locale.c \
+ messages.c talloc.c url.c utf8.c utils.c useragent.c
+S_DESKTOP := knockout.c options.c plot_style.c print.c search.c \
+ searchweb.c scroll.c textarea.c tree.c version.c
# S_COMMON are sources common to all builds
S_COMMON := $(addprefix content/,$(S_CONTENT)) \
@@ -33,8 +33,8 @@ S_PDF := $(addprefix desktop/save_pdf/,$(S_PDF))
# S_BROWSER are sources related to full browsers but are common
# between RISC OS, GTK, BeOS and AmigaOS builds
-S_BROWSER := browser.c frames.c history_core.c netsurf.c save_text.c \
- selection.c textinput.c
+S_BROWSER := browser.c frames.c history_core.c netsurf.c save_complete.c \
+ save_text.c selection.c textinput.c
S_BROWSER := $(addprefix desktop/,$(S_BROWSER))
# S_RISCOS are sources purely for the RISC OS build
@@ -42,9 +42,9 @@ S_RISCOS := 401login.c artworks.c assert.c awrender.s bitmap.c buffer.c \
cookies.c configure.c debugwin.c dialog.c download.c draw.c \
filetype.c font.c global_history.c gui.c help.c history.c \
hotlist.c image.c menus.c message.c palettes.c plotters.c \
- plugin.c print.c query.c save.c save_complete.c save_draw.c \
- save_pdf.c schedule.c search.c sprite.c sslcert.c textarea.c \
- textselection.c theme.c theme_install.c thumbnail.c \
+ plugin.c print.c query.c save.c save_draw.c save_pdf.c \
+ schedule.c search.c searchweb.c sprite.c sslcert.c \
+ textarea.c textselection.c theme.c theme_install.c thumbnail.c \
treeview.c ucstables.c uri.c url_complete.c url_protocol.c \
wimp.c wimp_event.c window.c gui/progress_bar.c \
gui/status_bar.c \
@@ -60,16 +60,19 @@ S_GTK := font_pango.c gtk_bitmap.c gtk_gui.c gtk_schedule.c \
gtk_thumbnail.c gtk_plotters.c gtk_treeview.c gtk_scaffolding.c \
gtk_completion.c gtk_login.c gtk_throbber.c gtk_selection.c \
gtk_history.c gtk_window.c gtk_filetype.c gtk_download.c \
- gtk_print.c gtk_tabs.c \
+ gtk_menu.c gtk_print.c gtk_save.c gtk_search.c gtk_tabs.c \
+ gtk_theme.c gtk_toolbar.c sexy_icon_entry.c \
$(addprefix dialogs/,gtk_options.c gtk_about.c gtk_source.c)
-S_GTK := $(addprefix gtk/,$(S_GTK))
+S_GTK := $(addprefix gtk/,$(S_GTK)) $(addprefix utils/,container.c)
+# code in utils/container.ch is non-universal it seems
# S_BEOS are sources purely for the BeOS build
S_BEOS := beos_about.cpp beos_bitmap.cpp beos_fetch_rsrc.cpp \
beos_filetype.cpp beos_font.cpp beos_gui.cpp beos_history.cpp \
beos_login.cpp beos_options.cpp beos_plotters.cpp \
- beos_scaffolding.cpp beos_schedule.cpp beos_thumbnail.cpp \
- beos_treeview.cpp beos_throbber.cpp beos_window.cpp
+ beos_scaffolding.cpp beos_search.cpp beos_schedule.cpp \
+ beos_thumbnail.cpp beos_treeview.cpp beos_throbber.cpp \
+ beos_window.cpp
S_BEOS := $(addprefix beos/,$(S_BEOS))
RDEF_BEOS := beos_res.rdef
RDEF_BEOS := $(addprefix beos/,$(RDEF_BEOS))
diff --git a/amiga/download.c b/amiga/download.c
index 48f719a60..baba92bd3 100644
--- a/amiga/download.c
+++ b/amiga/download.c
@@ -29,13 +29,13 @@
#include "amiga/download.h"
#include "amiga/object.h"
#include "amiga/options.h"
-#include "amiga/save_complete.h"
#include "amiga/bitmap.h"
#include "amiga/iff_dr2d.h"
#include "content/fetch.h"
#include "desktop/selection.h"
+#include "desktop/save_complete.h"
#include "utils/messages.h"
#include "utils/utils.h"
diff --git a/amiga/fetch_file.c b/amiga/fetch_file.c
index acc0d4724..953478423 100755
--- a/amiga/fetch_file.c
+++ b/amiga/fetch_file.c
@@ -215,11 +215,11 @@ void ami_fetch_file_free(void *vf)
static void ami_fetch_file_send_callback(fetch_msg msg,
struct ami_file_fetch_info *fetch, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
fetch->locked = true;
/* LOG(("ami file fetcher callback %ld",msg)); */
- fetch_send_callback(msg,fetch->fetch_handle,data,size);
+ fetch_send_callback(msg,fetch->fetch_handle,data,size,errorcode);
fetch->locked = false;
}
@@ -234,6 +234,7 @@ void ami_fetch_file_poll(const char *scheme_ignored)
struct nsObject *node;
struct nsObject *nnode;
struct ami_file_fetch_info *fetch;
+ fetch_error_code errorcode;
if(IsMinListEmpty(ami_file_fetcher_list)) return;
@@ -241,6 +242,7 @@ void ami_fetch_file_poll(const char *scheme_ignored)
do
{
+ errorcode = FETCH_ERROR_NO_ERROR;
nnode=(struct nsObject *)GetSucc((struct Node *)node);
fetch = (struct ami_file_fetch_info *)node->objstruct;
@@ -255,13 +257,19 @@ void ami_fetch_file_poll(const char *scheme_ignored)
len = FRead(fetch->fh,ami_file_fetcher_buffer,1,1024);
- ami_fetch_file_send_callback(FETCH_DATA,
- fetch,ami_file_fetcher_buffer,len);
+ if (len == (ULONG)-1)
+ errorcode = FETCH_ERROR_MISC;
+ else if (len > 0)
+ ami_fetch_file_send_callback(
+ FETCH_DATA, fetch,
+ ami_file_fetcher_buffer,
+ len, errorcode);
if((len<1024) && (!fetch->aborted))
{
ami_fetch_file_send_callback(FETCH_FINISHED,
- fetch, &fetch->cachedata, 0);
+ fetch, &fetch->cachedata, 0,
+ errorcode);
fetch->aborted = true;
}
@@ -284,7 +292,8 @@ void ami_fetch_file_poll(const char *scheme_ignored)
LOG(("mimetype %s len %ld",fetch->mimetype,fetch->len));
ami_fetch_file_send_callback(FETCH_TYPE,
- fetch, fetch->mimetype, (ULONG)fetch->len);
+ fetch, fetch->mimetype, (ULONG)fetch->len,
+ errorcode);
}
else
{
@@ -292,8 +301,11 @@ void ami_fetch_file_poll(const char *scheme_ignored)
errorstring = ASPrintf("%s %s",messages_get("FileError"),fetch->path);
fetch_set_http_code(fetch->fetch_handle,404);
+
+ errorcode = FETCH_ERROR_HTTP_NOT2;
ami_fetch_file_send_callback(FETCH_ERROR, fetch,
- errorstring, 0);
+ errorstring, 0,
+ errorcode);
fetch->aborted = true;
FreeVec(errorstring);
}
diff --git a/amiga/gui.c b/amiga/gui.c
index bd8d4cb28..ebd5d6657 100755
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -47,6 +47,7 @@
#include "amiga/menu.h"
#include "amiga/options.h"
#include <libraries/keymap.h>
+#include "desktop/save_complete.h"
#include "desktop/textinput.h"
#include <intuition/pointerclass.h>
#include <math.h>
@@ -66,7 +67,6 @@
#include "amiga/cookies.h"
#include "amiga/clipboard.h"
#include <proto/keymap.h>
-#include "amiga/save_complete.h"
#include "amiga/fetch_file.h"
#include "amiga/fetch_mailto.h"
#include "amiga/search.h"
@@ -3410,6 +3410,23 @@ void gui_window_stop_throbber(struct gui_window *g)
// g->shared->throbber_frame = 0;
}
+/**
+ * function to add retrieved favicon to gui
+ */
+void gui_window_set_icon(struct gui_window *g, struct content *icon)
+{
+}
+
+/**
+ * set gui display of a retrieved favicon representing the search
+ * provider
+ * \param ico may be NULL for local calls; then access current cache from
+ * search_web_ico()
+ */
+void gui_window_set_search_ico(struct content *ico)
+{
+}
+
void ami_update_throbber(struct gui_window_2 *g,bool redraw)
{
struct IBox *bbox;
diff --git a/amiga/gui.h b/amiga/gui.h
index ddf1dc9b2..47aace0db 100755
--- a/amiga/gui.h
+++ b/amiga/gui.h
@@ -56,6 +56,8 @@ enum
GID_NEXT,
GID_PREV,
GID_SEARCHSTRING,
+ GID_SHOWALL,
+ GID_CASE,
GID_HSCROLL,
GID_LAST
};
diff --git a/amiga/menu.c b/amiga/menu.c
index f80907ccd..7ceb9191d 100755
--- a/amiga/menu.c
+++ b/amiga/menu.c
@@ -30,13 +30,13 @@
#include "amiga/save_pdf.h"
#include "desktop/save_text.h"
#include "desktop/save_pdf/pdf_plotters.h"
+#include "desktop/save_complete.h"
#include <string.h>
#include "amiga/tree.h"
#include "amiga/history.h"
#include "amiga/cookies.h"
#include <proto/exec.h>
#include "amiga/arexx.h"
-#include "amiga/save_complete.h"
#include "utils/url.h"
#include <dos/anchorpath.h>
#include "desktop/textinput.h"
diff --git a/amiga/save_complete.c b/amiga/save_complete.c
index 29b58ba3b..1cadc2030 100755
--- a/amiga/save_complete.c
+++ b/amiga/save_complete.c
@@ -2,6 +2,7 @@
* Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
* Copyright 2004-2007 James Bursa <bursa@users.sourceforge.net>
* Copyright 2008 Chris Young <chris@unsatisfactorysoftware.co.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -18,807 +19,97 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Save HTML document with dependencies (implementation).
- */
-
-#include "utils/config.h"
-//#define _GNU_SOURCE /* for strndup */
-#include <assert.h>
#include <ctype.h>
-#include <errno.h>
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <regex.h>
#include <libxml/HTMLtree.h>
-#include <libxml/parserInternals.h>
-#include "utils/config.h"
-#include "css/css.h"
-#include "render/box.h"
-#include "amiga/save_complete.h"
-#include "utils/log.h"
-#include "utils/url.h"
+#include "desktop/save_complete.h"
#include "utils/utils.h"
-#include <proto/dos.h>
#include <proto/icon.h>
#include <workbench/icon.h>
-
-regex_t save_complete_import_re;
-
-/** An entry in save_complete_list. */
-struct save_complete_entry {
- struct content *content;
- struct save_complete_entry *next; /**< Next entry in list */
-};
-
-/** List of urls seen and saved so far. */
-static struct save_complete_entry *save_complete_list = 0;
-
-static bool save_complete_html(struct content *c, const char *path,
- bool index);
-static bool save_imported_sheets(struct content *c, const char *path);
-static char * rewrite_stylesheet_urls(const char *source, unsigned int size,
- int *osize, const char *base);
-static bool rewrite_document_urls(xmlDoc *doc, const char *base);
-static bool rewrite_urls(xmlNode *n, const char *base);
-static bool rewrite_url(xmlNode *n, const char *attr, const char *base);
-static bool save_complete_list_add(struct content *content);
-static struct content * save_complete_list_find(const char *url);
-static bool save_complete_list_check(struct content *content);
-/* static void save_complete_list_dump(void); */
-static bool save_complete_inventory(const char *path);
+#include "content/content.h"
/**
- * Save an HTML page with all dependencies.
- *
- * \param c CONTENT_HTML to save
- * \param path directory to save to (must exist)
- * \return true on success, false on error and error reported
- */
-
-bool save_complete(struct content *c, const char *path)
-{
- bool result;
-
- result = save_complete_html(c, path, true);
-
- if (result)
- result = save_complete_inventory(path);
-
- /* free save_complete_list */
- while (save_complete_list) {
- struct save_complete_entry *next = save_complete_list->next;
- free(save_complete_list);
- save_complete_list = next;
- }
-
- return result;
-}
-
-
-/**
- * Save an HTML page with all dependencies, recursing through imported pages.
- *
- * \param c CONTENT_HTML to save
- * \param path directory to save to (must exist)
- * \param index true to save as "index"
- * \return true on success, false on error and error reported
- */
-
-bool save_complete_html(struct content *c, const char *path, bool index)
-{
- char spath[256];
- unsigned int i;
- htmlParserCtxtPtr parser;
- BPTR fh = 0;
-
- if (c->type != CONTENT_HTML)
- return false;
-
- if (save_complete_list_check(c))
- return true;
-
- /* save stylesheets, ignoring the base and adblocking sheets */
- for (i = STYLESHEET_START; i != c->data.html.stylesheet_count; i++) {
- struct content *css = c->data.html.stylesheets[i].c;
- char *source;
- int source_len;
- bool is_style;
-
- if (!css)
- continue;
- if (save_complete_list_check(css))
- continue;
-
- is_style = (strcmp(css->url, c->data.html.base_url) == 0);
-
- if (is_style == false) {
- if (!save_complete_list_add(css)) {
- warn_user("NoMemory", 0);
- return false;
- }
- }
-
- if (!save_imported_sheets(css, path))
- return false;
-
- if (is_style)
- continue; /* don't save <style> elements */
-
- snprintf(spath, sizeof spath, "%s/%x", path,
- (unsigned int) css);
- source = rewrite_stylesheet_urls(css->source_data,
- css->source_size, &source_len, css->url);
- if (!source) {
- warn_user("NoMemory", 0);
- return false;
- }
-
-/*
- error = xosfile_save_stamped(spath, 0xf79, source,
- source + source_len);
+* conducts the filesystem save appropriate to the gui
+* \param path save path
+* \param filename name of file to save
+* \param len data length
+* \param sourcedata pointer to data to save, NULL when all data in c
+* \param type content type
+* \return true for success
*/
- if(fh = FOpen(spath,MODE_NEWFILE,0))
- {
- FWrite(fh,source,1,source_len);
- FClose(fh);
- SetComment(spath,c->url);
- }
-
- free(source);
-/*
- if (error) {
- LOG(("xosfile_save_stamped: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
- return false;
- }
-*/
- }
-
- /* save objects */
- for (i = 0; i != c->data.html.object_count; i++) {
- struct content *obj = c->data.html.object[i].content;
-
- /* skip difficult content types */
- if (!obj || obj->type >= CONTENT_OTHER || !obj->source_data)
- continue;
- if (save_complete_list_check(obj))
- continue;
-
- if (!save_complete_list_add(obj)) {
- warn_user("NoMemory", 0);
- return false;
- }
-
- if (obj->type == CONTENT_HTML) {
- if (!save_complete_html(obj, path, false))
- return false;
- continue;
- }
-
- snprintf(spath, sizeof spath, "%s/%x", path,
- (unsigned int) obj);
-/*
- error = xosfile_save_stamped(spath,
- ro_content_filetype(obj),
- obj->source_data,
- obj->source_data + obj->source_size);
- if (error) {
- LOG(("xosfile_save_stamped: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
- return false;
- }
-*/
- if(fh = FOpen(spath,MODE_NEWFILE,0))
- {
- FWrite(fh,obj->source_data,1,obj->source_size);
- FClose(fh);
- SetComment(spath,obj->url);
- }
-
- }
-
- /*save_complete_list_dump();*/
-
- /* make a copy of the document tree */
- parser = htmlCreateMemoryParserCtxt(c->source_data, c->source_size);
- if (!parser) {
+bool save_complete_gui_save(const char *path, const char *filename, size_t len,
+ const char *sourcedata, content_type type)
+{
+ int res;
+ int namelen;
+ char deftype[5];
+ struct DiskObject *dobj = NULL;
+ namelen = strlen(path) + strlen(filename) + 2;
+ char *fullpath = malloc(namelen);
+ if (!fullpath) {
warn_user("NoMemory", 0);
return false;
}
- /* set parser charset */
- if (c->data.html.encoding) {
- xmlCharEncodingHandler *enc_handler;
- enc_handler =
- xmlFindCharEncodingHandler(c->data.html.encoding);
- if (enc_handler) {
- xmlCtxtResetLastError(parser);
- if (xmlSwitchToEncoding(parser, enc_handler)) {
- xmlFreeDoc(parser->myDoc);
- htmlFreeParserCtxt(parser);
- warn_user("MiscError",
- "Encoding switch failed");
- return false;
- }
- }
- }
-
- htmlParseDocument(parser);
-
- /* rewrite all urls we know about */
- if (!rewrite_document_urls(parser->myDoc, c->data.html.base_url)) {
- xmlFreeDoc(parser->myDoc);
- htmlFreeParserCtxt(parser);
- warn_user("NoMemory", 0);
+ snprintf(fullpath, namelen, "%s/%s", path, filename);
+ FILE *f = fopen(fullpath, "w");
+ if (f == NULL)
return false;
- }
-
- /* save the html file out last of all */
- if (index)
+ res = fwrite(sourcedata, len, 1, f);
+ fclose(f);
+ switch(type)
{
- struct DiskObject *dobj = NULL;
-
- snprintf(spath, sizeof spath, "%s/index", path);
-
- dobj = GetIconTags(NULL,ICONGETA_GetDefaultName,"html",
- ICONGETA_GetDefaultType,WBPROJECT,
- TAG_DONE);
-
- PutIconTags(spath,dobj,
- ICONPUTA_NotifyWorkbench,TRUE,
- TAG_DONE);
- }
- else
- {
- snprintf(spath, sizeof spath, "%s/%x", path, (unsigned int)c);
- }
-
- errno = 0;
- if (htmlSaveFileFormat(spath, parser->myDoc, 0, 0) == -1) {
- if (errno)
- warn_user("SaveError", strerror(errno));
- else
- warn_user("SaveError", "htmlSaveFileFormat failed");
- return false;
- }
-
-/*
- error = xosfile_set_type(spath, 0xfaf);
- if (error) {
- LOG(("xosfile_set_type: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
- return false;
- }
-*/
-
- xmlFreeDoc(parser->myDoc);
- htmlFreeParserCtxt(parser);
-
- return true;
-}
-
-
-/**
- * Save stylesheets imported by a CONTENT_CSS.
- *
- * \param c a CONTENT_CSS
- * \param path path to save to
- * \return true on success, false on error and error reported
- */
-
-bool save_imported_sheets(struct content *c, const char *path)
-{
- char spath[256];
- unsigned int j;
- char *source;
- int source_len;
- BPTR fh = 0;
-
- for (j = 0; j != c->data.css.import_count; j++) {
- struct content *css = c->data.css.imports[j].c;
-
- if (!css)
- continue;
- if (save_complete_list_check(css))
- continue;
-
- if (!save_complete_list_add(css)) {
- warn_user("NoMemory", 0);
- return false;
- }
-
- if (!save_imported_sheets(css, path))
- return false;
-
- snprintf(spath, sizeof spath, "%s/%x", path,
- (unsigned int) css);
- source = rewrite_stylesheet_urls(css->source_data,
- css->source_size, &source_len, css->url);
- if (!source) {
- warn_user("NoMemory", 0);
- return false;
- }
-
- if(fh = FOpen(spath,MODE_NEWFILE,0))
- {
- FWrite(fh,source,1,source_len);
- FClose(fh);
- SetComment(spath,c->url);
- }
-/*
- error = xosfile_save_stamped(spath, 0xf79, source,
- source + source_len);
-*/
- free(source);
-/*
- if (error) {
- LOG(("xosfile_save_stamped: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
- return false;
- }
-*/
- }
-
- return true;
-}
-
-
-/**
- * Initialise the save_complete module.
- */
-
-void save_complete_init(void)
-{
- /* Match an @import rule - see CSS 2.1 G.1. */
- regcomp_wrapper(&save_complete_import_re,
- "@import" /* IMPORT_SYM */
- "[ \t\r\n\f]*" /* S* */
- /* 1 */
- "(" /* [ */
- /* 2 3 */
- "\"(([^\"]|[\\]\")*)\"" /* STRING (approximated) */
- "|"
- /* 4 5 */
- "'(([^']|[\\]')*)'"
- "|" /* | */
- "url\\([ \t\r\n\f]*" /* URI (approximated) */
- /* 6 7 */
- "\"(([^\"]|[\\]\")*)\""
- "[ \t\r\n\f]*\\)"
- "|"
- "url\\([ \t\r\n\f]*"
- /* 8 9 */
- "'(([^']|[\\]')*)'"
- "[ \t\r\n\f]*\\)"
- "|"
- "url\\([ \t\r\n\f]*"
- /* 10 */
- "([^) \t\r\n\f]*)"
- "[ \t\r\n\f]*\\)"
- ")", /* ] */
- REG_EXTENDED | REG_ICASE);
-}
-
-
-/**
- * Rewrite stylesheet \@import rules for save complete.
- *
- * @param source stylesheet source
- * @param size size of source
- * @param osize updated with the size of the result
- * @param base url of stylesheet
- * @return converted source, or 0 on out of memory
- */
-
-char * rewrite_stylesheet_urls(const char *source, unsigned int size,
- int *osize, const char *base)
-{
- char *res;
- const char *url;
- char *url2;
- char buf[20];
- unsigned int offset = 0;
- int url_len = 0;
- struct content *content;
- int m;
- unsigned int i;
- unsigned int imports = 0;
- regmatch_t match[11];
- url_func_result result;
-
- /* count number occurences of @import to (over)estimate result size */
- /* can't use strstr because source is not 0-terminated string */
- for (i = 0; 7 < size && i != size - 7; i++) {
- if (source[i] == '@' &&
- tolower(source[i + 1]) == 'i' &&
- tolower(source[i + 2]) == 'm' &&
- tolower(source[i + 3]) == 'p' &&
- tolower(source[i + 4]) == 'o' &&
- tolower(source[i + 5]) == 'r' &&
- tolower(source[i + 6]) == 't')
- imports++;
- }
-
- res = malloc(size + imports * 20);
- if (!res)
- return 0;
- *osize = 0;
-
- while (offset < size) {
- m = regexec(&save_complete_import_re, source + offset,
- 11, match, 0);
- if (m)
+ case CONTENT_HTML:
+ strcpy(deftype,"html");
break;
-
- /*for (unsigned int i = 0; i != 11; i++) {
- if (match[i].rm_so == -1)
- continue;
- fprintf(stderr, "%i: '%.*s'\n", i,
- match[i].rm_eo - match[i].rm_so,
- source + offset + match[i].rm_so);
- }*/
-
- url = 0;
- if (match[2].rm_so != -1) {
- url = source + offset + match[2].rm_so;
- url_len = match[2].rm_eo - match[2].rm_so;
- } else if (match[4].rm_so != -1) {
- url = source + offset + match[4].rm_so;
- url_len = match[4].rm_eo - match[4].rm_so;
- } else if (match[6].rm_so != -1) {
- url = source + offset + match[6].rm_so;
- url_len = match[6].rm_eo - match[6].rm_so;
- } else if (match[8].rm_so != -1) {
- url = source + offset + match[8].rm_so;
- url_len = match[8].rm_eo - match[8].rm_so;
- } else if (match[10].rm_so != -1) {
- url = source + offset + match[10].rm_so;
- url_len = match[10].rm_eo - match[10].rm_so;
- }
- assert(url);
-
- url2 = strndup(url, url_len);
- if (!url2) {
- free(res);
- return 0;
- }
- result = url_join(url2, base, (char**)&url);
- free(url2);
- if (result == URL_FUNC_NOMEM) {
- free(res);
- return 0;
- }
-
- /* copy data before match */
- memcpy(res + *osize, source + offset, match[0].rm_so);
- *osize += match[0].rm_so;
-
- if (result == URL_FUNC_OK) {
- content = save_complete_list_find(url);
- if (content) {
- /* replace import */
- snprintf(buf, sizeof buf, "@import '%x'",
- (unsigned int) content);
- memcpy(res + *osize, buf, strlen(buf));
- *osize += strlen(buf);
- } else {
- /* copy import */
- memcpy(res + *osize, source + offset + match[0].rm_so,
- match[0].rm_eo - match[0].rm_so);
- *osize += match[0].rm_eo - match[0].rm_so;
- }
- }
- else {
- /* copy import */
- memcpy(res + *osize, source + offset + match[0].rm_so,
- match[0].rm_eo - match[0].rm_so);
- *osize += match[0].rm_eo - match[0].rm_so;
- }
-
- assert(0 < match[0].rm_eo);
- offset += match[0].rm_eo;
- }
-
- /* copy rest of source */
- if (offset < size) {
- memcpy(res + *osize, source + offset, size - offset);
- *osize += size - offset;
- }
-
- return res;
-}
-
-
-/**
- * Rewrite URLs in a HTML document to be relative.
- *
- * \param doc root of the document tree
- * \param base base url of document
- * \return true on success, false on out of memory
- */
-
-bool rewrite_document_urls(xmlDoc *doc, const char *base)
-{
- xmlNode *node;
-
- for (node = doc->children; node; node = node->next)
- if (node->type == XML_ELEMENT_NODE)
- if (!rewrite_urls(node, base))
- return false;
-
- return true;
-}
-
-
-/**
- * Traverse tree, rewriting URLs as we go.
- *
- * \param n xmlNode of type XML_ELEMENT_NODE to rewrite
- * \param base base url of document
- * \return true on success, false on out of memory
- *
- * URLs in the tree rooted at element n are rewritten.
- */
-
-bool rewrite_urls(xmlNode *n, const char *base)
-{
- xmlNode *child;
-
- assert(n->type == XML_ELEMENT_NODE);
-
- /**
- * We only need to consider the following cases:
- *
- * Attribute: Elements:
- *
- * 1) data <object>
- * 2) href <a> <area> <link>
- * 3) src <script> <input> <frame> <iframe> <img>
- * 4) n/a <style>
- * 5) n/a any <base> tag
- * 6) background any (except those above)
- */
- if (!n->name) {
- /* ignore */
- }
- /* 1 */
- else if (strcmp(n->name, "object") == 0) {
- if (!rewrite_url(n, "data", base))
- return false;
- }
- /* 2 */
- else if (strcmp(n->name, "a") == 0 ||
- strcmp(n->name, "area") == 0 ||
- strcmp(n->name, "link") == 0) {
- if (!rewrite_url(n, "href", base))
- return false;
- }
- /* 3 */
- else if (strcmp(n->name, "frame") == 0 ||
- strcmp(n->name, "iframe") == 0 ||
- strcmp(n->name, "input") == 0 ||
- strcmp(n->name, "img") == 0 ||
- strcmp(n->name, "script") == 0) {
- if (!rewrite_url(n, "src", base))
+ case CONTENT_CSS:
+ strcpy(deftype,"css");
+ break;
+ default:
+ free(fullpath);
return false;
+ break;
}
- /* 4 */
- else if (strcmp(n->name, "style") == 0) {
- unsigned int len;
- xmlChar *content;
-
- for (child = n->children; child != 0; child = child->next) {
- /* Get current content */
- content = xmlNodeGetContent(child);
- if (!content)
- /* unfortunately we don't know if this is
- * due to memory exhaustion, or because
- * there is no content for this node */
- continue;
-
- /* Rewrite @import rules */
- char *rewritten = rewrite_stylesheet_urls(
- content,
- strlen((char*)content),
- &len, base);
- xmlFree(content);
- if (!rewritten)
- return false;
-
- /* set new content */
- xmlNodeSetContentLen(child,
- (const xmlChar*)rewritten,
- len);
- }
-
- return true;
- }
- /* 5 */
- else if (strcmp(n->name, "base") == 0) {
- /* simply remove any <base> tags from the document */
- xmlUnlinkNode(n);
- xmlFreeNode(n);
- /* base tags have no content, so there's no point recursing
- * additionally, we've just destroyed this node, so trying
- * to recurse would result in bad things happening */
- return true;
- }
- /* 6 */
- else {
- if (!rewrite_url(n, "background", base))
- return false;
- }
-
- /* now recurse */
- for (child = n->children; child;) {
- /* we must extract the next child now, as if the current
- * child is a <base> element, it will be removed from the
- * tree (see 5, above), thus preventing extraction of the
- * next child */
- xmlNode *next = child->next;
- if (child->type == XML_ELEMENT_NODE) {
- if (!rewrite_urls(child, base))
- return false;
- }
- child = next;
- }
-
- return true;
-}
-
-
-/**
- * Rewrite an URL in a HTML document.
- *
- * \param n The node to modify
- * \param attr The html attribute to modify
- * \param base base url of document
- * \return true on success, false on out of memory
- */
-
-bool rewrite_url(xmlNode *n, const char *attr, const char *base)
-{
- char *url, *data;
- char rel[20];
- struct content *content;
- url_func_result res;
-
- if (!xmlHasProp(n, (const xmlChar *) attr))
- return true;
-
- data = xmlGetProp(n, (const xmlChar *) attr);
- if (!data)
- return false;
-
- res = url_join(data, base, &url);
- xmlFree(data);
- if (res == URL_FUNC_NOMEM)
- return false;
- else if (res == URL_FUNC_OK) {
- content = save_complete_list_find(url);
- if (content) {
- /* found a match */
- free(url);
- snprintf(rel, sizeof rel, "%x",
- (unsigned int) content);
- if (!xmlSetProp(n, (const xmlChar *) attr,
- (xmlChar *) rel))
- return false;
- } else {
- /* no match found */
- if (!xmlSetProp(n, (const xmlChar *) attr,
- (xmlChar *) url)) {
- free(url);
- return false;
- }
- free(url);
- }
- }
-
- return true;
-}
-
-
-/**
- * Add a content to the save_complete_list.
- *
- * \param content content to add
- * \return true on success, false on out of memory
- */
-
-bool save_complete_list_add(struct content *content)
-{
- struct save_complete_entry *entry;
- entry = malloc(sizeof (*entry));
- if (!entry)
+
+ dobj = GetIconTags(NULL,ICONGETA_GetDefaultName,deftype,
+ ICONGETA_GetDefaultType,WBPROJECT,
+ TAG_DONE);
+
+ PutIconTags(fullpath, dobj,
+ ICONPUTA_NotifyWorkbench, TRUE, TAG_DONE);
+ free(fullpath);
+ if (res != 1)
return false;
- entry->content = content;
- entry->next = save_complete_list;
- save_complete_list = entry;
return true;
}
-
/**
- * Look up a url in the save_complete_list.
- *
- * \param url url to find
- * \return content if found, 0 otherwise
- */
-
-struct content * save_complete_list_find(const char *url)
-{
- struct save_complete_entry *entry;
- for (entry = save_complete_list; entry; entry = entry->next)
- if (strcmp(url, entry->content->url) == 0)
- return entry->content;
- return 0;
-}
-
-
-/**
- * Look up a content in the save_complete_list.
- *
- * \param content pointer to content
- * \return true if the content is in the save_complete_list
- */
-
-bool save_complete_list_check(struct content *content)
-{
- struct save_complete_entry *entry;
- for (entry = save_complete_list; entry; entry = entry->next)
- if (entry->content == content)
- return true;
- return false;
-}
-
-
-#if 0
-/**
- * Dump save complete list to stderr
- */
-void save_complete_list_dump(void)
-{
- struct save_complete_entry *entry;
- for (entry = save_complete_list; entry; entry = entry->next)
- fprintf(stderr, "%p : %s\n", entry->content,
- entry->content->url);
-}
-#endif
-
-
-/**
- * Create the inventory file listing original URLs.
- */
+* wrapper for lib function htmlSaveFileFormat; front sets path from
+* path + filename in a filesystem-specific way
+*/
-bool save_complete_inventory(const char *path)
+int save_complete_htmlSaveFileFormat(const char *path, const char *filename,
+ xmlDocPtr cur, const char *encoding, int format)
{
- char spath[256];
- FILE *fp;
-
- snprintf(spath, sizeof spath, "%s/Inventory", path);
-
- fp = fopen(spath, "w");
- if (!fp) {
- LOG(("fopen(): errno = %i", errno));
- warn_user("SaveError", strerror(errno));
- return false;
- }
-
- struct save_complete_entry *entry;
- for (entry = save_complete_list; entry; entry = entry->next)
- fprintf(fp, "%x %s\n",
- (unsigned int) entry->content,
- entry->content->url);
-
- fclose(fp);
-
- return true;
+ int ret;
+ int len = strlen(path) + strlen(filename) + 2;
+ struct DiskObject *dobj = NULL;
+ char *fullpath = malloc(len);
+ if (!fullpath){
+ warn_user("NoMemory", 0);
+ return -1;
+ }
+ snprintf(fullpath, len, "%s/%s", path, filename);
+ ret = htmlSaveFileFormat(fullpath, cur, encoding, format);
+ dobj = GetIconTags(NULL,ICONGETA_GetDefaultName, "html",
+ ICONGETA_GetDefaultType,WBPROJECT,
+ TAG_DONE);
+
+ PutIconTags(fullpath, dobj,
+ ICONPUTA_NotifyWorkbench, TRUE, TAG_DONE);
+
+ free(fullpath);
+ return ret;
}
diff --git a/amiga/search.c b/amiga/search.c
index 1de08a50c..b5008a89b 100755
--- a/amiga/search.c
+++ b/amiga/search.c
@@ -28,6 +28,7 @@
#include "content/content.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
+#include "desktop/search.h"
#include "desktop/selection.h"
#include "render/box.h"
#include "render/html.h"
@@ -44,10 +45,12 @@
#include <proto/string.h>
#include <proto/button.h>
#include <proto/label.h>
+#include <proto/checkbox.h>
#include <classes/window.h>
#include <gadgets/layout.h>
#include <gadgets/string.h>
#include <gadgets/button.h>
+#include <gadgets/checkbox.h>
#include <images/label.h>
#include <reaction/reaction_macros.h>
@@ -68,580 +71,25 @@ struct list_entry {
struct list_entry *next;
};
-struct gui_window *search_current_window = NULL;
+static bool search_insert;
-static char *search_string = NULL;
-static struct list_entry search_head = { 0, 0, NULL, NULL, NULL, NULL, NULL };
-static struct list_entry *search_found = &search_head;
-static struct list_entry *search_current = NULL;
-static struct content *search_content = NULL;
-static bool search_prev_case_sens = false;
static struct find_window *fwin = NULL;
-#define RECENT_SEARCHES 8
-bool search_insert;
-static char *recent_search[RECENT_SEARCHES];
-
-static void start_search(bool forwards,char *search_string);
-static void do_search(char *string, int string_len, bool case_sens,
- bool forwards);
-static const char *find_pattern(const char *string, int s_len,
- const char *pattern, int p_len, bool case_sens, int *m_len);
-static bool find_occurrences_html(const char *pattern, int p_len,
- struct box *cur, bool case_sens);
-static bool find_occurrences_text(const char *pattern, int p_len,
- struct content *c, bool case_sens);
-static struct list_entry *add_entry(unsigned start_idx, unsigned end_idx);
-static void free_matches(void);
-static void show_all(bool all);
-static void show_status(bool found);
-/**
- * Begins/continues the search process
- * Note that this may be called many times for a single search.
- *
- * \param forwards search forwards from start/current position
- */
-
-void start_search(bool forwards,char *string)
-{
- int string_len;
- int i = 0;
-
- string_len = strlen(string);
- for(i = 0; i < string_len; i++)
- if (string[i] != '#' && string[i] != '*') break;
- if (i >= string_len) {
- free_matches();
- show_status(true);
-
- RefreshSetGadgetAttrs(fwin->gadgets[GID_PREV],fwin->win,NULL,
- GA_Disabled,TRUE,
- TAG_DONE);
-
- RefreshSetGadgetAttrs(fwin->gadgets[GID_NEXT],fwin->win,NULL,
- GA_Disabled,TRUE,
- TAG_DONE);
-
- gui_window_set_scroll(search_current_window, 0, 0);
- return;
- }
-
- do_search(string, string_len,
- false, // case sensitivity
- forwards);
-}
-
-/**
- * Ends the search process, invalidating all global state and
- * freeing the list of found boxes
- *
- * \param w the search window handle (not used)
- */
-void ami_gui_search_end(void)
-{
- search_current_window = 0;
-
- if (search_string) {
- //ro_gui_search_add_recent(search_string);
- free(search_string);
- }
- search_string = 0;
-
- free_matches();
-
- search_current = 0;
-
- search_content = 0;
-
- search_prev_case_sens = false;
-}
-
-
-/**
- * Release the memory used by the list of matches,
- * deleting selection objects too
- */
-
-void free_matches(void)
-{
- struct list_entry *a = search_found->next;
- struct list_entry *b;
-
- /* empty the list before clearing and deleting the
- selections because the the clearing updates the
- screen immediately, causing nested accesses to the list */
-
- search_found->prev = 0;
- search_found->next = 0;
-
- for (; a; a = b) {
- b = a->next;
- if (a->sel) {
- selection_clear(a->sel, true);
- selection_destroy(a->sel);
- }
- free(a);
- }
-}
-
-
-/**
- * Search for a string in the box tree
- *
- * \param string the string to search for
- * \param string_len length of search string
- * \param case_sens whether to perform a case sensitive search
- * \param forwards direction to search in
- */
-void do_search(char *string, int string_len, bool case_sens, bool forwards)
-{
- struct rect bounds;
- struct content *c;
- struct box *box;
- bool new = false;
-
- if (!search_current_window)
- return;
-
- c = search_current_window->shared->bw->current_content;
-
- /* only handle html contents */
- if ((!c) || (c->type != CONTENT_HTML &&
- c->type != CONTENT_TEXTPLAIN))
- return;
-
- box = c->data.html.layout;
-
- if (!box)
- return;
-
-// LOG(("do_search '%s' - '%s' (%p, %p) %p (%d, %d) %d",
-// search_string, string, search_content, c, search_found->next,
-// search_prev_case_sens, case_sens, forwards));
-
- /* check if we need to start a new search or continue an old one */
- if (!search_string || c != search_content || !search_found->next ||
- search_prev_case_sens != case_sens ||
- (case_sens && strcmp(string, search_string) != 0) ||
- (!case_sens && strcasecmp(string, search_string) != 0)) {
- bool res;
-
- if (search_string)
- free(search_string);
- search_current = 0;
- free_matches();
-
- search_string = malloc(string_len + 1);
- if (search_string) {
- memcpy(search_string, string, string_len);
- search_string[string_len] = '\0';
- }
-
-// xhourglass_on();
-
- if (c->type == CONTENT_HTML)
- res = find_occurrences_html(string, string_len,
- box, case_sens);
- else {
- assert(c->type == CONTENT_TEXTPLAIN);
- res = find_occurrences_text(string, string_len,
- c, case_sens);
- }
-
- if (!res) {
- free_matches();
- //xhourglass_off();
- return;
- }
- //xhourglass_off();
-
- new = true;
- search_content = c;
- search_prev_case_sens = case_sens;
- }
-
-// LOG(("%d %p %p (%p, %p)", new, search_found->next, search_current, search_current->prev, search_current->next));
-
- if (new) {
- /* new search, beginning at the top of the page */
- search_current = search_found->next;
- }
- else if (search_current) {
- /* continued search in the direction specified */
- if (forwards) {
- if (search_current->next)
- search_current = search_current->next;
- }
- else {
- if (search_current->prev)
- search_current = search_current->prev;
- }
- }
-
- show_status(search_current != NULL);
- show_all(false);
-
- RefreshSetGadgetAttrs(fwin->gadgets[GID_PREV],fwin->win,NULL,
- GA_Disabled,(!search_current || !search_current->prev),
- TAG_DONE);
-
- RefreshSetGadgetAttrs(fwin->gadgets[GID_NEXT],fwin->win,NULL,
- GA_Disabled,(!search_current || !search_current->next),
- TAG_DONE);
-
- if (!search_current)
- return;
-
- switch (c->type) {
- case CONTENT_HTML:
- /* get box position and jump to it */
- box_coords(search_current->start_box,
- &bounds.x0, &bounds.y0);
- /* \todo: move x0 in by correct idx */
- box_coords(search_current->end_box,
- &bounds.x1, &bounds.y1);
- /* \todo: move x1 in by correct idx */
- bounds.x1 += search_current->end_box->width;
- bounds.y1 += search_current->end_box->height;
- break;
-
- default:
- assert(c->type == CONTENT_TEXTPLAIN);
- textplain_coords_from_range(c,
- search_current->start_idx,
- search_current->end_idx, &bounds);
- break;
- }
-
- gui_window_scroll_visible(search_current_window,
- bounds.x0, bounds.y0, bounds.x1, bounds.y1);
-}
-
-
-/**
- * Find the first occurrence of 'match' in 'string' and return its index
- *
- * /param string the string to be searched (unterminated)
- * /param s_len length of the string to be searched
- * /param pattern the pattern for which we are searching (unterminated)
- * /param p_len length of pattern
- * /param case_sens true iff case sensitive match required
- * /param m_len accepts length of match in bytes
- * /return pointer to first match, NULL if none
- */
-
-const char *find_pattern(const char *string, int s_len, const char *pattern,
- int p_len, bool case_sens, int *m_len)
-{
- struct { const char *ss, *s, *p; bool first; } context[16];
- const char *ep = pattern + p_len;
- const char *es = string + s_len;
- const char *p = pattern - 1; /* a virtual '*' before the pattern */
- const char *ss = string;
- const char *s = string;
- bool first = true;
- int top = 0;
-
- while (p < ep) {
- bool matches;
- if (p < pattern || *p == '*') {
- char ch;
-
- /* skip any further asterisks; one is the same as many */
- do p++; while (p < ep && *p == '*');
-
- /* if we're at the end of the pattern, yes, it matches */
- if (p >= ep) break;
-
- /* anything matches a # so continue matching from
- here, and stack a context that will try to match
- the wildcard against the next character */
-
- ch = *p;
- if (ch != '#') {
- /* scan forwards until we find a match for this char */
- if (!case_sens) ch = toupper(ch);
- while (s < es) {
- if (case_sens) {
- if (*s == ch) break;
- } else if (toupper(*s) == ch)
- break;
- s++;
- }
- }
-
- if (s < es) {
- /* remember where we are in case the match fails;
- we can then resume */
- if (top < (int)NOF_ELEMENTS(context)) {
- context[top].ss = ss;
- context[top].s = s + 1;
- context[top].p = p - 1; /* ptr to last asterisk */
- context[top].first = first;
- top++;
- }
-
- if (first) {
- ss = s; /* remember first non-'*' char */
- first = false;
- }
-
- matches = true;
- }
- else
- matches = false;
- }
- else if (s < es) {
- char ch = *p;
- if (ch == '#')
- matches = true;
- else {
- if (case_sens)
- matches = (*s == ch);
- else
- matches = (toupper(*s) == toupper(ch));
- }
- if (matches && first) {
- ss = s; /* remember first non-'*' char */
- first = false;
- }
- }
- else
- matches = false;
-
- if (matches) {
- p++; s++;
- }
- else {
- /* doesn't match, resume with stacked context if we have one */
- if (--top < 0) return NULL; /* no match, give up */
-
- ss = context[top].ss;
- s = context[top].s;
- p = context[top].p;
- first = context[top].first;
- }
- }
-
- /* end of pattern reached */
- *m_len = max(s - ss, 1);
- return ss;
-}
-
-
-/**
- * Finds all occurrences of a given string in the html box tree
- *
- * \param pattern the string pattern to search for
- * \param p_len pattern length
- * \param cur pointer to the current box
- * \param case_sens whether to perform a case sensitive search
- * \return true on success, false on memory allocation failure
- */
-bool find_occurrences_html(const char *pattern, int p_len, struct box *cur,
- bool case_sens)
-{
- struct box *a;
-
- /* ignore this box, if there's no visible text */
- if (!cur->object && cur->text) {
- const char *text = cur->text;
- unsigned length = cur->length;
-
- while (length > 0) {
- struct list_entry *entry;
- unsigned match_length;
- unsigned match_offset;
- const char *new_text;
- const char *pos = find_pattern(text, length,
- pattern, p_len, case_sens,
- &match_length);
- if (!pos) break;
-
- /* found string in box => add to list */
- match_offset = pos - cur->text;
-
- entry = add_entry(cur->byte_offset + match_offset,
- cur->byte_offset +
- match_offset +
- match_length);
- if (!entry)
- return false;
-
- entry->start_box = cur;
- entry->end_box = cur;
-
- new_text = pos + match_length;
- length -= (new_text - text);
- text = new_text;
- }
- }
-
- /* and recurse */
- for (a = cur->children; a; a = a->next) {
- if (!find_occurrences_html(pattern, p_len, a, case_sens))
- return false;
- }
-
- return true;
-}
-
-
-/**
- * Finds all occurrences of a given string in a textplain content
- *
- * \param pattern the string pattern to search for
- * \param p_len pattern length
- * \param c the content to be searched
- * \param case_sens wheteher to perform a case sensitive search
- * \return true on success, false on memory allocation failure
- */
-
-bool find_occurrences_text(const char *pattern, int p_len,
- struct content *c, bool case_sens)
-{
- int nlines = textplain_line_count(c);
- int line;
-
- for(line = 0; line < nlines; line++) {
- size_t offset, length;
- const char *text = textplain_get_line(c, line,
- &offset, &length);
- if (text) {
- while (length > 0) {
- struct list_entry *entry;
- unsigned match_length;
- size_t start_idx;
- const char *new_text;
- const char *pos = find_pattern(text, length,
- pattern, p_len, case_sens,
- &match_length);
- if (!pos) break;
-
- /* found string in line => add to list */
- start_idx = offset + (pos - text);
- entry = add_entry(start_idx, start_idx +
- match_length);
- if (!entry)
- return false;
-
- new_text = pos + match_length;
- offset += (new_text - text);
- length -= (new_text - text);
- text = new_text;
- }
- }
- }
-
- return true;
-}
-
-
-/**
- * Add a new entry to the list of matches
- *
- * \param start_idx offset of match start within textual representation
- * \param end_idx offset of match end
- * \return pointer to added entry, NULL iff failed
- */
-
-struct list_entry *add_entry(unsigned start_idx, unsigned end_idx)
-{
- struct list_entry *entry;
-
- /* found string in box => add to list */
- entry = calloc(1, sizeof(*entry));
- if (!entry) {
- warn_user("NoMemory", 0);
- return NULL;
- }
-
- entry->start_idx = start_idx;
- entry->end_idx = end_idx;
- entry->sel = NULL;
-
- entry->next = 0;
- entry->prev = search_found->prev;
- if (!search_found->prev)
- search_found->next = entry;
- else
- search_found->prev->next = entry;
- search_found->prev = entry;
-
- return entry;
-}
-
-
-/**
- * Determines whether any portion of the given text box should be
- * selected because it matches the current search string.
- *
- * \param g gui window
- * \param start_offset byte offset within text of string to be checked
- * \param end_offset byte offset within text
- * \param start_idx byte offset within string of highlight start
- * \param end_idx byte offset of highlight end
- * \return true iff part of the box should be highlighted
- */
-
-bool gui_search_term_highlighted(struct gui_window *g,
- unsigned start_offset, unsigned end_offset,
- unsigned *start_idx, unsigned *end_idx)
-{
- if (g == search_current_window) {
- struct list_entry *a;
- for(a = search_found->next; a; a = a->next)
- if (a->sel && selection_defined(a->sel) &&
- selection_highlighted(a->sel,
- start_offset, end_offset,
- start_idx, end_idx))
- return true;
- }
-
- return false;
-}
-
-
-/**
- * Specifies whether all matches or just the current match should
- * be highlighted in the search text.
- */
-
-void show_all(bool all)
-{
- struct list_entry *a;
-
- for (a = search_found->next; a; a = a->next) {
- bool add = true;
- if (!all && a != search_current) {
- add = false;
- if (a->sel) {
- selection_clear(a->sel, true);
- selection_destroy(a->sel);
- a->sel = NULL;
- }
- }
- if (add && !a->sel) {
- a->sel = selection_create(search_current_window->shared->bw);
- if (a->sel) {
- struct content *c = search_current_window->shared->bw->current_content;
- switch (c->type) {
- case CONTENT_HTML:
- selection_init(a->sel,
- c->data.html.layout);
- break;
- default:
- assert(c->type ==
- CONTENT_TEXTPLAIN);
- selection_init(a->sel, NULL);
- break;
- }
- selection_set_start(a->sel, a->start_idx);
- selection_set_end(a->sel, a->end_idx);
- }
- }
- }
-}
+search_flags_t ami_search_flags(void);
+char *ami_search_string(void);
+static void ami_search_set_status(bool found, void *p);
+static void ami_search_set_hourglass(bool active, void *p);
+static void ami_search_add_recent(const char *string, void *p);
+static void ami_search_set_forward_state(bool active, void *p);
+static void ami_search_set_back_state(bool active, void *p);
+
+static struct search_callbacks ami_search_callbacks = {
+ ami_search_set_forward_state,
+ ami_search_set_back_state,
+ ami_search_set_status,
+ ami_search_set_hourglass,
+ ami_search_add_recent
+};
/**
@@ -649,15 +97,6 @@ void show_all(bool all)
*
* \param found search pattern matched in text
*/
-
-void show_status(bool found)
-{
-/*
- ro_gui_set_icon_string(dialog_search, ICON_SEARCH_STATUS,
- found ? "" : messages_get("NotFound"), true);
-*/
-}
-
void ami_search_open(struct gui_window *gwin)
{
struct content *c = gwin->shared->bw->current_content;
@@ -667,12 +106,18 @@ void ami_search_open(struct gui_window *gwin)
c->type != CONTENT_TEXTPLAIN))
return;
- search_current_window = gwin;
+ if (gwin->shared->bw->search_context == NULL)
+ search_create_context(gwin->shared->bw,
+ &ami_search_callbacks, NULL);
search_insert = true;
if(fwin)
{
- ami_gui_search_end();
+ if(fwin->gwin->shared->bw->search_context != NULL)
+ search_destroy_context(fwin->gwin->shared->bw->
+ search_context);
+ ami_search_set_forward_state(true, NULL);
+ ami_search_set_back_state(true, NULL);
fwin->gwin->shared->searchwin = NULL;
fwin->gwin = gwin;
gwin->shared->searchwin = fwin;
@@ -709,6 +154,21 @@ void ami_search_open(struct gui_window *gwin)
LabelEnd,
*/
CHILD_WeightedHeight,0,
+ LAYOUT_AddChild, fwin->gadgets[GID_CASE] = CheckBoxObject,
+ GA_ID,GID_CASE,
+ GA_Text,messages_get("CaseSens"),
+ GA_Selected,FALSE,
+ GA_TabCycle,TRUE,
+ GA_RelVerify,TRUE,
+ CheckBoxEnd,
+ LAYOUT_AddChild, fwin->gadgets[GID_SHOWALL] = CheckBoxObject,
+ GA_ID,GID_SHOWALL,
+ GA_Text,messages_get("ShowAll"),
+ GA_Selected,FALSE,
+ GA_TabCycle,TRUE,
+ GA_RelVerify,TRUE,
+ CheckBoxEnd,
+
LAYOUT_AddChild, HGroupObject,
LAYOUT_AddChild, fwin->gadgets[GID_PREV] = ButtonObject,
GA_ID,GID_PREV,
@@ -739,7 +199,10 @@ void ami_search_open(struct gui_window *gwin)
void ami_search_close(void)
{
- ami_gui_search_end();
+ if (fwin->gwin->shared->bw->search_context != NULL)
+ search_destroy_context(fwin->gwin->shared->bw->search_context);
+ ami_search_set_forward_state(true, NULL);
+ ami_search_set_back_state(true, NULL);
fwin->gwin->shared->searchwin = NULL;
DisposeObject(fwin->objects[OID_MAIN]);
DelObject(fwin->node);
@@ -752,44 +215,158 @@ BOOL ami_search_event(void)
ULONG class,result,relevent = 0;
ULONG column;
uint16 code;
- char *text;
+ search_flags_t flags;
while((result = RA_HandleInput(fwin->objects[OID_MAIN],&code)) != WMHI_LASTMSG)
{
switch(result & WMHI_CLASSMASK) // class
- {
- case WMHI_GADGETUP:
- switch(result & WMHI_GADGETMASK)
- {
- case GID_NEXT:
- search_insert = true;
- GetAttr(STRINGA_TextVal,fwin->gadgets[GID_SEARCHSTRING],(ULONG *)&text);
- start_search(true,text);
- break;
-
- case GID_PREV:
- search_insert = true;
- GetAttr(STRINGA_TextVal,fwin->gadgets[GID_SEARCHSTRING],(ULONG *)&text);
- start_search(false,text);
- break;
-
- case GID_SEARCHSTRING:
- RefreshSetGadgetAttrs(fwin->gadgets[GID_PREV],fwin->win,NULL,
- GA_Disabled,FALSE,
- TAG_DONE);
-
- RefreshSetGadgetAttrs(fwin->gadgets[GID_NEXT],fwin->win,NULL,
- GA_Disabled,FALSE,
- TAG_DONE);
- break;
- }
+ {
+ case WMHI_GADGETUP:
+ switch(result & WMHI_GADGETMASK)
+ {
+ case GID_NEXT:
+ search_insert = true;
+ flags = SEARCH_FLAG_FORWARDS |
+ ami_search_flags();
+ if (search_verify_new(
+ search_data.search_window,
+ &ami_search_callbacks, NULL))
+ search_step(fwin->gwin->shared->bw,
+ flags,
+ ami_search_string());
break;
- case WMHI_CLOSEWINDOW:
- ami_search_close();
- return TRUE;
+ case GID_PREV:
+ search_insert = true;
+ flags = ~SEARCH_FLAG_FORWARDS &
+ ami_search_flags();
+ if (search_verify_new(
+ search_data.search_window,
+ &ami_search_callbacks, NULL))
+ search_step(fwin->gwin->shared->bw,
+ flags,
+ ami_search_string());
+ break;
+
+ case GID_SEARCHSTRING:
+ if (fwin->gwin->shared->
+ bw->search_context
+ != NULL)
+ search_destroy_context(
+ fwin->gwin->
+ shared->bw->
+ search_context);
+ ami_search_set_forward_state(
+ true, NULL);
+ ami_search_set_back_state(
+ true, NULL);
+
+ RefreshSetGadgetAttrs(fwin->gadgets[GID_PREV],fwin->win,NULL,
+ GA_Disabled,FALSE,
+ TAG_DONE);
+
+ RefreshSetGadgetAttrs(fwin->gadgets[GID_NEXT],fwin->win,NULL,
+ GA_Disabled,FALSE,
+ TAG_DONE);
break;
}
+ break;
+
+ case WMHI_CLOSEWINDOW:
+ ami_search_close();
+ return TRUE;
+ break;
+ }
}
return FALSE;
}
+
+/**
+* Change the displayed search status.
+* \param found search pattern matched in text
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void ami_search_set_status(bool found, void *p)
+{
+}
+
+/**
+* display hourglass while searching
+* \param active start/stop indicator
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void ami_search_set_hourglass(bool active, void *p)
+{
+ SetWindowPointer(fwin->win,
+ WA_BusyPointer,active,
+ WA_PointerDelay,active,
+ TAG_DONE);
+}
+
+/**
+* retrieve string being searched for from gui
+*/
+
+char *ami_search_string(void)
+{
+ char *text;
+ GetAttr(STRINGA_TextVal,fwin->gadgets[GID_SEARCHSTRING],(ULONG *)&text);
+ return text;
+
+}
+
+/**
+* add search string to recent searches list
+* front is at liberty how to implement the bare notification
+* should normally store a strdup() of the string;
+* core gives no guarantee of the integrity of the const char *
+* \param string search pattern
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void ami_search_add_recent(const char *string, void *p)
+{
+}
+
+/**
+* activate search forwards button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void ami_search_set_forward_state(bool active, void *p)
+{
+ RefreshSetGadgetAttrs(fwin->gadgets[GID_NEXT],fwin->win,NULL,
+ GA_Disabled, active ? FALSE : TRUE, TAG_DONE);
+
+}
+
+/**
+* activate search forwards button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void ami_search_set_back_state(bool active, void *p)
+{
+ RefreshSetGadgetAttrs(fwin->gadgets[GID_PREV],fwin->win,NULL,
+ GA_Disabled, active ? FALSE : TRUE, TAG_DONE);
+}
+
+/**
+* retrieve state of 'case sensitive', 'show all' checks in gui
+*/
+
+search_flags_t ami_search_flags(void)
+{
+ ULONG case_sensitive, showall;
+ search_flags_t flags;
+ GetAttr(GA_Selected,fwin->gadgets[GID_CASE],(ULONG *)&case_sensitive);
+ GetAttr(GA_Selected,fwin->gadgets[GID_SHOWALL],(ULONG *)&showall);
+ flags = 0 | (case_sensitive ? SEARCH_FLAG_CASE_SENSITIVE : 0) |
+ (showall ? SEARCH_FLAG_SHOWALL : 0);
+ return flags;
+}
+
diff --git a/beos/beos_scaffolding.cpp b/beos/beos_scaffolding.cpp
index cd6f01e38..7b12d433e 100644
--- a/beos/beos_scaffolding.cpp
+++ b/beos/beos_scaffolding.cpp
@@ -2311,6 +2311,22 @@ void gui_window_stop_throbber(struct gui_window* _g)
g->top_view->UnlockLooper();
}
+/**
+ * add retrieved favicon to the gui
+ */
+void gui_window_set_icon(struct gui_window *g, struct content *icon)
+{
+}
+
+/**
+* set gui display of a retrieved favicon representing the search provider
+* \param ico may be NULL for local calls; then access current cache from
+* search_web_ico()
+*/
+void gui_window_set_search_ico(struct content *ico)
+{
+}
+
#warning XXX
#if 0 /* GTK */
gboolean nsbeos_scaffolding_is_busy(nsbeos_scaffolding *scaffold)
diff --git a/beos/beos_search.cpp b/beos/beos_search.cpp
new file mode 100644
index 000000000..9a6905fd5
--- /dev/null
+++ b/beos/beos_search.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+extern "C" {
+#include "utils/log.h"
+}
+/* callback functions for search implementation */
+static void gui_search_set_status(bool found, void *p);
+static void gui_search_set_hourglass(bool active, void *p);
+static void gui_search_add_recent(const char *string, void *p);
+static void gui_search_set_forward_state(bool active, void *p);
+static void gui_search_set_back_state(bool active, void *p);
+
+/**
+ * Change the displayed search status.
+ * \param found search pattern matched in text
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_status(bool found, void *p)
+{
+}
+
+/**
+ * display hourglass while searching
+ * \param active start/stop indicator
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_hourglass(bool active, void *p)
+{
+}
+
+/**
+ * add search string to recent searches list
+ * \param string search pattern
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_add_recent(const char *string, void *p)
+{
+}
+
+/**
+ * activate search forwards button in gui
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_forward_state(bool active, void *p)
+{
+}
+
+/**
+ * activate search forwards button in gui
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+void gui_search_set_back_state(bool active, void *p)
+{
+}
diff --git a/content/content.c b/content/content.c
index e00f3bcd6..8b6cfd47d 100644
--- a/content/content.c
+++ b/content/content.c
@@ -155,6 +155,9 @@ static const struct mime_entry mime_map[] = {
{"image/svg", CONTENT_SVG},
{"image/svg+xml", CONTENT_SVG},
#endif
+#ifdef WITH_BMP
+ {"image/vnd.microsoft.icon", CONTENT_ICO},
+#endif
#ifdef WITH_ARTWORKS
{"image/x-artworks", CONTENT_ARTWORKS},
#endif
diff --git a/content/fetch.c b/content/fetch.c
index a1417fee9..4fdeffb3d 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -601,11 +601,11 @@ bool fetch_get_verifiable(struct fetch *fetch)
void
fetch_send_callback(fetch_msg msg, struct fetch *fetch, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
/*LOG(("Fetcher sending callback. Fetch %p, fetcher %p data %p size %lu",
fetch, fetch->fetcher_handle, data, size)); */
- fetch->callback(msg, fetch->p, data, size);
+ fetch->callback(msg, fetch->p, data, size, errorcode);
}
diff --git a/content/fetch.h b/content/fetch.h
index 3206acc39..2666b8ffc 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -40,6 +40,19 @@ typedef enum {
FETCH_CERT_ERR,
} fetch_msg;
+typedef enum {
+ FETCH_ERROR_NO_ERROR,
+ FETCH_ERROR_CERT,
+ FETCH_ERROR_AUTHENTICATION,
+ FETCH_ERROR_HTTP_NOT2,
+ FETCH_ERROR_COULDNT_RESOLVE_HOST,
+ FETCH_ERROR_PARTIAL_FILE,
+ FETCH_ERROR_MEMORY,
+ FETCH_ERROR_URL,
+ FETCH_ERROR_ENCODING,
+ FETCH_ERROR_MISC
+} fetch_error_code;
+
struct content;
struct fetch;
struct form_successful_control;
@@ -58,7 +71,7 @@ struct ssl_cert_info {
extern bool fetch_active;
typedef void (*fetch_callback)(fetch_msg msg, void *p, const void *data,
- unsigned long size);
+ unsigned long size, fetch_error_code errorcode);
void fetch_init(void);
@@ -105,7 +118,8 @@ bool fetch_add_fetcher(const char *scheme,
fetcher_finalise finaliser);
void fetch_send_callback(fetch_msg msg, struct fetch *fetch,
- const void *data, unsigned long size);
+ const void *data, unsigned long size,
+ fetch_error_code errorcode);
void fetch_remove_from_queues(struct fetch *fetch);
void fetch_free(struct fetch *f);
void fetch_set_http_code(struct fetch *fetch, long http_code);
diff --git a/content/fetchcache.c b/content/fetchcache.c
index 8643cc1a2..87732d49e 100644
--- a/content/fetchcache.c
+++ b/content/fetchcache.c
@@ -38,6 +38,8 @@
#include "content/content.h"
#include "content/fetchcache.h"
#include "content/fetch.h"
+#include "desktop/options.h"
+#include "desktop/searchweb.h"
#include "content/urldb.h"
#include "utils/log.h"
#include "utils/messages.h"
@@ -49,17 +51,23 @@
static char error_page[1000];
static regex_t re_content_type;
static void fetchcache_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size);
+ unsigned long size, fetch_error_code errorcode);
static char *fetchcache_parse_type(const char *s, char **params[]);
static void fetchcache_parse_header(struct content *c, const char *data,
size_t size);
-static void fetchcache_error_page(struct content *c, const char *error);
+static void fetchcache_error_page(struct content *c, const char *error,
+ fetch_error_code errorcode);
+static void fetchcache_search_redirect(struct content *c, const char *error);
static void fetchcache_cache_update(struct content *c);
static void fetchcache_cache_clone(struct content *c,
const struct cache_data *data);
static void fetchcache_notmodified(struct content *c, const void *data);
static void fetchcache_redirect(struct content *c, const void *data,
unsigned long size);
+static void fetchcache_redirect_common(struct content *c, bool verifiable,
+ const char *url, const char *referer,
+ struct content *parent);
+
static void fetchcache_auth(struct content *c, const char *realm);
@@ -276,7 +284,8 @@ void fetchcache_go(struct content *content, const char *referer,
callback(CONTENT_MSG_ERROR,
content, p1, p2, msg_data);
} else {
- fetchcache_error_page(content, error_message);
+ fetchcache_error_page(content, error_message,
+ FETCH_ERROR_NO_ERROR);
}
return;
@@ -366,7 +375,8 @@ void fetchcache_go(struct content *content, const char *referer,
content_broadcast(content, CONTENT_MSG_ERROR,
msg_data);
} else {
- fetchcache_error_page(content, error_message);
+ fetchcache_error_page(content, error_message,
+ FETCH_ERROR_NO_ERROR);
}
}
@@ -405,7 +415,7 @@ void fetchcache_go(struct content *content, const char *referer,
*/
void fetchcache_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
bool res;
struct content *c = p;
@@ -506,7 +516,7 @@ void fetchcache_callback(fetch_msg msg, void *p, const void *data,
msg_data);
} else {
content_reset(c);
- fetchcache_error_page(c, data);
+ fetchcache_error_page(c, data, errorcode);
}
break;
@@ -721,17 +731,29 @@ void fetchcache_parse_header(struct content *c, const char *data,
/**
- * Generate an error page.
- *
+ * Generate an error page. Optionally redirect to web search provider
* \param c empty content to generate the page in
* \param error message to display
*/
-void fetchcache_error_page(struct content *c, const char *error)
+void fetchcache_error_page(struct content *c, const char *error,
+ fetch_error_code errorcode)
{
const char *params[] = { 0 };
int length;
-
+ char *host;
+
+ if (option_search_url_bar) {
+ if (url_host(c->url, &host) != URL_FUNC_OK) {
+ warn_user(messages_get("NoMemory"), 0);
+ } else if ((strcasecmp(host, search_web_provider_host())
+ != 0) && (errorcode ==
+ FETCH_ERROR_COULDNT_RESOLVE_HOST)) {
+ fetchcache_search_redirect(c, error);
+ free(host);
+ return;
+ }
+ }
if ((length = snprintf(error_page, sizeof(error_page),
messages_get("ErrorPage"), error)) < 0)
length = 0;
@@ -746,6 +768,27 @@ void fetchcache_error_page(struct content *c, const char *error)
c->fresh = false;
}
+void fetchcache_search_redirect(struct content *c, const char *error)
+{
+ char *redirurl, *temp;
+
+ /* clear http:// plus trailing / from url, it is already escaped */
+ temp = strdup(c->url + SLEN("http://"));
+ if (temp == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ temp[strlen(temp)-1] = '\0';
+ redirurl = search_web_get_url(temp);
+ if (redirurl == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+
+ fetchcache_redirect_common(c, false, redirurl, NULL, c);
+ free(redirurl);
+ return;
+}
/**
* Update a content's cache state
@@ -930,7 +973,6 @@ void fetchcache_redirect(struct content *c, const void *data,
long http_code;
const char *ref;
struct content *parent;
- bool can_fetch;
bool parent_was_verifiable;
union content_msg_data msg_data;
url_func_result result;
@@ -1056,32 +1098,50 @@ void fetchcache_redirect(struct content *c, const void *data,
}
free(scheme);
-
- /* Determine if we've got a fetch handler for this url */
- can_fetch = fetch_can_fetch(url);
+ fetchcache_redirect_common(c, parent_was_verifiable, url, referer, parent);
+ free(url);
+ free(referer);
+}
+
+/**
+ * common logic from fetchcache_redirect() / fetchcache_search_redirect()
+ * \param c the content param from the original function
+ * \param verifiable parent_was_verifiable [false for search_redirect]
+ * \param url the url being considered; caller retains ownership
+ * \param referer referer [ / NULL particularly for search_redirect]
+ * \param parent parent content [ / c for search_redirect]
+ */
+void fetchcache_redirect_common(struct content *c, bool verifiable,
+ const char *url, const char *referer, struct content *parent)
+{
+ union content_msg_data msg_data;
+ bool can_fetch;
+ /* check there's a fetch handler */
+ can_fetch = fetch_can_fetch(url);
+
/* Process users of this content */
while (c->user_list->next) {
intptr_t p1, p2;
void (*callback)(content_msg msg,
- struct content *c, intptr_t p1,
- intptr_t p2,
- union content_msg_data data);
+ struct content *c, intptr_t p1,
+ intptr_t p2,
+ union content_msg_data data);
struct content *replacement;
-
+
p1 = c->user_list->next->p1;
p2 = c->user_list->next->p2;
callback = c->user_list->next->callback;
-
+
/* If we can't fetch this url, attempt to launch it */
if (!can_fetch) {
msg_data.launch_url = url;
callback(CONTENT_MSG_LAUNCH, c, p1, p2, msg_data);
}
-
+
/* Remove user */
content_remove_user(c, callback, p1, p2);
-
+
if (can_fetch) {
/* Get replacement content -- HTTP GET request */
@@ -1101,37 +1161,29 @@ void fetchcache_redirect(struct content *c, const void *data,
*/
replacement = fetchcache(url, callback, p1, p2,
c->width, c->height, c->no_error_pages,
- NULL, NULL, parent_was_verifiable,
+ NULL, NULL, verifiable,
c->download);
if (!replacement) {
msg_data.error = messages_get("BadRedirect");
content_broadcast(c, CONTENT_MSG_ERROR,
msg_data);
-
- free(url);
- free(referer);
return;
- }
-
+ }
/* Set replacement's redirect count to 1 greater
* than ours */
replacement->redirect_count = c->redirect_count + 1;
-
+
/* Notify user that content has changed */
msg_data.new_url = url;
callback(CONTENT_MSG_NEWPTR, replacement,
- p1, p2, msg_data);
-
+ p1, p2, msg_data);
+
/* Start fetching the replacement content */
fetchcache_go(replacement, referer, callback, p1, p2,
- c->width, c->height, NULL, NULL,
- parent_was_verifiable, parent);
+ c->width, c->height, NULL, NULL,
+ verifiable, parent);
}
}
-
- /* Clean up */
- free(url);
- free(referer);
}
/**
@@ -1218,7 +1270,8 @@ void fetchcache_auth(struct content *c, const char *realm)
msg_data.error = error_message;
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
} else {
- fetchcache_error_page(c, error_message);
+ fetchcache_error_page(c, error_message,
+ FETCH_ERROR_URL);
}
}
diff --git a/content/fetchers/fetch_curl.c b/content/fetchers/fetch_curl.c
index 8efe0d726..67b74ef99 100644
--- a/content/fetchers/fetch_curl.c
+++ b/content/fetchers/fetch_curl.c
@@ -748,6 +748,7 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
{
bool finished = false;
bool error = false;
+ fetch_error_code errorcode = FETCH_ERROR_NO_ERROR;
bool cert = false;
bool abort_fetch;
struct curl_fetch_info *f;
@@ -778,8 +779,10 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
* Content-Length header. */
if (!f->had_headers && fetch_curl_process_headers(f))
; /* redirect with partial body, or similar */
- else
+ else {
error = true;
+ errorcode = FETCH_ERROR_PARTIAL_FILE;
+ }
} else if (result == CURLE_WRITE_ERROR && f->stopped)
/* CURLE_WRITE_ERROR occurs when fetch_curl_data
* returns 0, which we use to abort intentionally */
@@ -790,9 +793,14 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
memset(f->cert_data, 0, sizeof(f->cert_data));
cert = true;
}
+ else if (result == CURLE_COULDNT_RESOLVE_HOST) {
+ error = true;
+ errorcode = FETCH_ERROR_COULDNT_RESOLVE_HOST;
+ }
else {
LOG(("Unknown cURL response code %d", result));
error = true;
+ errorcode = FETCH_ERROR_MISC;
}
fetch_curl_stop(f);
@@ -800,7 +808,7 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
if (abort_fetch)
; /* fetch was aborted: no callback */
else if (finished)
- fetch_send_callback(FETCH_FINISHED, f->fetch_handle, 0, 0);
+ fetch_send_callback(FETCH_FINISHED, f->fetch_handle, 0, 0, errorcode);
else if (cert) {
int i;
BIO *mem;
@@ -877,14 +885,14 @@ void fetch_curl_done(CURL *curl_handle, CURLcode result)
if (certs[i].cert->references == 0)
X509_free(certs[i].cert);
}
-
+ errorcode = FETCH_ERROR_CERT;
fetch_send_callback(FETCH_CERT_ERR, f->fetch_handle,
- &ssl_certs, i);
+ &ssl_certs, i, errorcode);
}
else if (error)
fetch_send_callback(FETCH_ERROR, f->fetch_handle,
- fetch_error_buffer, 0);
+ fetch_error_buffer, 0, errorcode);
fetch_free(f->fetch_handle);
}
@@ -910,14 +918,16 @@ int fetch_curl_progress(void *clientp, double dltotal, double dlnow,
human_friendly_bytesize(dlnow),
human_friendly_bytesize(dltotal));
fetch_send_callback(FETCH_PROGRESS, f->fetch_handle,
- fetch_progress_buffer,
- (unsigned long) percent);
+ fetch_progress_buffer,
+ (unsigned long) percent,
+ FETCH_ERROR_NO_ERROR);
} else {
snprintf(fetch_progress_buffer, 255,
messages_get("ProgressU"),
human_friendly_bytesize(dlnow));
fetch_send_callback(FETCH_PROGRESS, f->fetch_handle,
- fetch_progress_buffer, 0);
+ fetch_progress_buffer, 0,
+ FETCH_ERROR_NO_ERROR);
}
return 0;
@@ -977,7 +987,8 @@ size_t fetch_curl_data(char *data, size_t size, size_t nmemb,
/* send data to the caller */
/*LOG(("FETCH_DATA"));*/
- fetch_send_callback(FETCH_DATA, f->fetch_handle, data, size * nmemb);
+ fetch_send_callback(FETCH_DATA, f->fetch_handle, data, size * nmemb,
+ FETCH_ERROR_NO_ERROR);
if (f->abort) {
f->stopped = true;
@@ -1006,7 +1017,8 @@ size_t fetch_curl_header(char *data, size_t size, size_t nmemb,
return 0;
}
- fetch_send_callback(FETCH_HEADER, f->fetch_handle, data, size);
+ fetch_send_callback(FETCH_HEADER, f->fetch_handle, data, size,
+ FETCH_ERROR_NO_ERROR);
#define SKIP_ST(o) for (i = (o); i < (int) size && (data[i] == ' ' || data[i] == '\t'); i++)
@@ -1100,20 +1112,23 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
if (http_code == 304 && !f->post_urlenc && !f->post_multipart) {
/* Not Modified && GET request */
- fetch_send_callback(FETCH_NOTMODIFIED, f->fetch_handle, 0, 0);
+ fetch_send_callback(FETCH_NOTMODIFIED, f->fetch_handle, 0, 0,
+ FETCH_ERROR_NO_ERROR);
return true;
}
/* handle HTTP redirects (3xx response codes) */
if (300 <= http_code && http_code < 400 && f->location != 0) {
LOG(("FETCH_REDIRECT, '%s'", f->location));
- fetch_send_callback(FETCH_REDIRECT, f->fetch_handle, f->location, 0);
+ fetch_send_callback(FETCH_REDIRECT, f->fetch_handle,
+ f->location, 0, FETCH_ERROR_NO_ERROR);
return true;
}
/* handle HTTP 401 (Authentication errors) */
if (http_code == 401) {
- fetch_send_callback(FETCH_AUTH, f->fetch_handle, f->realm,0);
+ fetch_send_callback(FETCH_AUTH, f->fetch_handle, f->realm,0,
+ FETCH_ERROR_AUTHENTICATION);
return true;
}
@@ -1121,7 +1136,8 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
if (f->only_2xx && strncmp(f->url, "http", 4) == 0 &&
(http_code < 200 || 299 < http_code)) {
fetch_send_callback(FETCH_ERROR, f->fetch_handle,
- messages_get("Not2xx"), 0);
+ messages_get("Not2xx"), 0,
+ FETCH_ERROR_HTTP_NOT2);
return true;
}
@@ -1141,7 +1157,7 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
"ETag: \"%10d\"", (int) s.st_mtime);
/* And send it to the header handler */
fetch_send_callback(FETCH_HEADER, f->fetch_handle, etag_buf,
- strlen(etag_buf));
+ strlen(etag_buf), FETCH_ERROR_NO_ERROR);
/* don't set last modified time so as to ensure that local
* files are revalidated at all times. */
@@ -1151,7 +1167,7 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
f->last_modified > s.st_mtime &&
f->file_etag == s.st_mtime) {
fetch_send_callback(FETCH_NOTMODIFIED, f->fetch_handle,
- 0, 0);
+ 0, 0, FETCH_ERROR_NO_ERROR);
curl_free(url_path);
return true;
}
@@ -1167,7 +1183,7 @@ bool fetch_curl_process_headers(struct curl_fetch_info *f)
curl_free(url_path);
LOG(("FETCH_TYPE, '%s'", type));
- fetch_send_callback(FETCH_TYPE, f->fetch_handle, type, f->content_length);
+ fetch_send_callback(FETCH_TYPE, f->fetch_handle, type, f->content_length, FETCH_ERROR_NO_ERROR);
if (f->abort)
return true;
diff --git a/content/fetchers/fetch_data.c b/content/fetchers/fetch_data.c
index 30274f51e..5b40b4ef6 100644
--- a/content/fetchers/fetch_data.c
+++ b/content/fetchers/fetch_data.c
@@ -129,10 +129,10 @@ static void fetch_data_abort(void *ctx)
static void fetch_data_send_callback(fetch_msg msg,
struct fetch_data_context *c, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
c->locked = true;
- fetch_send_callback(msg, c->parent_fetch, data, size);
+ fetch_send_callback(msg, c->parent_fetch, data, size, errorcode);
c->locked = false;
}
@@ -154,7 +154,7 @@ static bool fetch_data_process(struct fetch_data_context *c)
if (strlen(c->url) < 6) {
/* 6 is the minimum possible length (data:,) */
fetch_data_send_callback(FETCH_ERROR, c,
- "Malformed data: URL", 0);
+ "Malformed data: URL", 0, FETCH_ERROR_URL);
return false;
}
@@ -164,7 +164,7 @@ static bool fetch_data_process(struct fetch_data_context *c)
/* find the comma */
if ( (comma = strchr(params, ',')) == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Malformed data: URL", 0);
+ "Malformed data: URL", 0, FETCH_ERROR_URL);
return false;
}
@@ -179,7 +179,7 @@ static bool fetch_data_process(struct fetch_data_context *c)
if (c->mimetype == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
"Unable to allocate memory for mimetype in data: URL",
- 0);
+ 0, FETCH_ERROR_MEMORY);
return false;
}
@@ -198,7 +198,8 @@ static bool fetch_data_process(struct fetch_data_context *c)
c->datalen = templen;
if (unescaped == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Unable to URL decode data: URL", 0);
+ "Unable to URL decode data: URL", 0,
+ FETCH_ERROR_ENCODING);
return false;
}
@@ -207,7 +208,8 @@ static bool fetch_data_process(struct fetch_data_context *c)
if (base64_decode(unescaped, c->datalen, c->data,
&(c->datalen)) == false) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Unable to Base64 decode data: URL", 0);
+ "Unable to Base64 decode data: URL", 0,
+ FETCH_ERROR_ENCODING);
curl_free(unescaped);
return false;
}
@@ -215,7 +217,8 @@ static bool fetch_data_process(struct fetch_data_context *c)
c->data = malloc(c->datalen);
if (c->data == NULL) {
fetch_data_send_callback(FETCH_ERROR, c,
- "Unable to allocate memory for data: URL", 0);
+ "Unable to allocate memory for data: URL", 0,
+ FETCH_ERROR_MEMORY);
curl_free(unescaped);
return false;
}
@@ -271,14 +274,17 @@ static void fetch_data_poll(const char *scheme)
* call to fetch_data_send_callback().
*/
fetch_data_send_callback(FETCH_TYPE,
- c, c->mimetype, c->datalen);
+ c, c->mimetype, c->datalen,
+ FETCH_ERROR_NO_ERROR);
if (!c->aborted) {
fetch_data_send_callback(FETCH_DATA,
- c, c->data, c->datalen);
+ c, c->data, c->datalen,
+ FETCH_ERROR_NO_ERROR);
}
if (!c->aborted) {
fetch_data_send_callback(FETCH_FINISHED,
- c, &cachedata, 0);
+ c, &cachedata, 0,
+ FETCH_ERROR_NO_ERROR);
}
} else {
LOG(("Processing of %s failed!", c->url));
diff --git a/desktop/browser.c b/desktop/browser.c
index cf28006c5..1072c3b22 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -87,12 +87,13 @@ static bool browser_window_check_throbber(struct browser_window *bw);
static void browser_window_convert_to_download(struct browser_window *bw);
static void browser_window_start_throbber(struct browser_window *bw);
static void browser_window_stop_throbber(struct browser_window *bw);
+static void browser_window_set_icon(struct browser_window *bw);
static void browser_window_set_status(struct browser_window *bw,
const char *text);
static void browser_window_set_pointer(struct gui_window *g,
gui_pointer_shape shape);
static void download_window_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size);
+ unsigned long size, fetch_error_code errorcode);
static void browser_window_destroy_children(struct browser_window *bw);
static void browser_window_destroy_internal(struct browser_window *bw);
static void browser_window_set_scale_internal(struct browser_window *bw,
@@ -167,6 +168,7 @@ struct browser_window *browser_window_create(const char *url,
if (url)
browser_window_go(bw, url, referer, history_add);
+
return bw;
}
@@ -418,8 +420,6 @@ void browser_window_callback(content_msg msg, struct content *c,
}
#endif
else {
- browser_window_refresh_url_bar(bw, c->url, bw->frag_id);
-
bw->refresh_interval = -1;
browser_window_set_status(bw, c->status_message);
}
@@ -491,6 +491,7 @@ void browser_window_callback(content_msg msg, struct content *c,
browser_window_update(bw, false);
browser_window_set_status(bw, c->status_message);
browser_window_stop_throbber(bw);
+ browser_window_set_icon(bw);
history_update(bw->history, c);
hotlist_visited(c);
free(bw->referer);
@@ -764,6 +765,21 @@ bool browser_window_check_throbber(struct browser_window *bw)
return false;
}
+/**
+ * when ready, set icon at top level
+ * \param bw browser_window
+ * current implementation ignores lower-levels' link rels completely
+ */
+void browser_window_set_icon(struct browser_window *bw)
+{
+ while (bw->parent)
+ bw = bw->parent;
+ if ((bw->current_content != NULL) && (bw->current_content->type == CONTENT_HTML))
+ gui_window_set_icon(bw->window,
+ bw->current_content->data.html.favicon);
+ else
+ gui_window_set_icon(bw->window, NULL);
+}
/**
* Redraw browser window, set extent to content, and update title.
@@ -1298,7 +1314,7 @@ void browser_window_find_target_internal(struct browser_window *bw,
*/
void download_window_callback(fetch_msg msg, void *p, const void *data,
- unsigned long size)
+ unsigned long size, fetch_error_code errorcode)
{
struct gui_download_window *download_window = p;
diff --git a/desktop/browser.h b/desktop/browser.h
index 8f9c2760e..ee777c832 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -170,6 +170,9 @@ struct browser_window {
/** Last time a link was followed in this window */
unsigned int last_action;
+
+ /** search context for free text search */
+ struct search_context *search_context;
struct form_control *visible_select_menu;
};
diff --git a/desktop/gui.h b/desktop/gui.h
index 6449c1edb..ca557ef8a 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -56,8 +56,7 @@ typedef enum { GUI_POINTER_DEFAULT, GUI_POINTER_POINT, GUI_POINTER_CARET,
#include "utils/config.h"
#include "content/content.h"
#include "desktop/browser.h"
-
-extern struct gui_window *search_current_window;
+#include "desktop/search.h"
void gui_init(int argc, char** argv);
void gui_init2(int argc, char** argv);
@@ -67,6 +66,7 @@ void gui_quit(void);
struct gui_window *gui_create_browser_window(struct browser_window *bw,
struct browser_window *clone, bool new_tab);
+struct browser_window *gui_window_get_browser_window(struct gui_window *g);
void gui_window_destroy(struct gui_window *g);
void gui_window_set_title(struct gui_window *g, const char *title);
void gui_window_redraw(struct gui_window *g, int x0, int y0, int x1, int y1);
@@ -88,6 +88,8 @@ void gui_window_hide_pointer(struct gui_window *g);
void gui_window_set_url(struct gui_window *g, const char *url);
void gui_window_start_throbber(struct gui_window *g);
void gui_window_stop_throbber(struct gui_window *g);
+void gui_window_set_icon(struct gui_window *g, struct content *icon);
+void gui_window_set_search_ico(struct content *ico);
void gui_window_place_caret(struct gui_window *g, int x, int y, int height);
void gui_window_remove_caret(struct gui_window *g);
void gui_window_new_content(struct gui_window *g);
@@ -125,7 +127,8 @@ void gui_launch_url(const char *url);
bool gui_search_term_highlighted(struct gui_window *g,
unsigned start_offset, unsigned end_offset,
- unsigned *start_idx, unsigned *end_idx);
+ unsigned *start_idx, unsigned *end_idx,
+ struct search_context *context);
struct ssl_cert_info;
diff --git a/desktop/options.c b/desktop/options.c
index 41896bfc7..1b639527d 100644
--- a/desktop/options.c
+++ b/desktop/options.c
@@ -111,12 +111,16 @@ char *option_ca_bundle = 0;
char *option_ca_path = 0;
/** Cookie file location */
char *option_cookie_file = 0;
-/** Cookie jar loaction */
+/** Cookie jar location */
char *option_cookie_jar = 0;
/** Home page location */
char *option_homepage_url = 0;
+/** search web from url bar */
+bool option_search_url_bar = false;
/** URL completion in url bar */
bool option_url_suggestion = true;
+/** default web search provider */
+int option_search_provider = 0;
/** default x position of new windows */
int option_window_x = 0;
/** default y position of new windows */
@@ -231,6 +235,8 @@ struct {
{ "cookie_file", OPTION_STRING, &option_cookie_file },
{ "cookie_jar", OPTION_STRING, &option_cookie_jar },
{ "homepage_url", OPTION_STRING, &option_homepage_url },
+ { "search_url_bar", OPTION_BOOL, &option_search_url_bar},
+ { "search_provider", OPTION_INTEGER, &option_search_provider},
{ "url_suggestion", OPTION_BOOL, &option_url_suggestion },
{ "window_x", OPTION_INTEGER, &option_window_x },
{ "window_y", OPTION_INTEGER, &option_window_y },
diff --git a/desktop/options.h b/desktop/options.h
index a25160818..ca92ee90a 100644
--- a/desktop/options.h
+++ b/desktop/options.h
@@ -70,6 +70,8 @@ extern char *option_ca_path;
extern char *option_cookie_file;
extern char *option_cookie_jar;
extern char *option_homepage_url;
+extern bool option_search_url_bar;
+extern int option_search_provider;
extern bool option_target_blank;
extern bool option_button_2_tab;
extern bool option_url_suggestion;
diff --git a/riscos/save_complete.c b/desktop/save_complete.c
index 3ac559784..48438908d 100644
--- a/riscos/save_complete.c
+++ b/desktop/save_complete.c
@@ -33,13 +33,11 @@
#include <regex.h>
#include <libxml/HTMLtree.h>
#include <libxml/parserInternals.h>
-#include "oslib/osfile.h"
#include "utils/config.h"
#include "content/content.h"
#include "css/css.h"
#include "render/box.h"
-#include "riscos/gui.h"
-#include "riscos/save_complete.h"
+#include "desktop/save_complete.h"
#include "utils/log.h"
#include "utils/url.h"
#include "utils/utils.h"
@@ -52,22 +50,28 @@ struct save_complete_entry {
struct save_complete_entry *next; /**< Next entry in list */
};
-/** List of urls seen and saved so far. */
-static struct save_complete_entry *save_complete_list = 0;
-
static bool save_complete_html(struct content *c, const char *path,
- bool index);
-static bool save_imported_sheets(struct content *c, const char *path);
+ bool index, struct save_complete_entry **list);
+static bool save_imported_sheets(struct content *c, const char *path,
+ struct save_complete_entry **list);
static char * rewrite_stylesheet_urls(const char *source, unsigned int size,
- int *osize, const char *base);
-static bool rewrite_document_urls(xmlDoc *doc, const char *base);
-static bool rewrite_urls(xmlNode *n, const char *base);
-static bool rewrite_url(xmlNode *n, const char *attr, const char *base);
-static bool save_complete_list_add(struct content *content);
-static struct content * save_complete_list_find(const char *url);
-static bool save_complete_list_check(struct content *content);
+ int *osize, const char *base,
+ struct save_complete_entry *list);
+static bool rewrite_document_urls(xmlDoc *doc, const char *base,
+ struct save_complete_entry *list);
+static bool rewrite_urls(xmlNode *n, const char *base,
+ struct save_complete_entry *list);
+static bool rewrite_url(xmlNode *n, const char *attr, const char *base,
+ struct save_complete_entry *list);
+static bool save_complete_list_add(struct content *content,
+ struct save_complete_entry **list);
+static struct content * save_complete_list_find(const char *url,
+ struct save_complete_entry *list);
+static bool save_complete_list_check(struct content *content,
+ struct save_complete_entry *list);
/* static void save_complete_list_dump(void); */
-static bool save_complete_inventory(const char *path);
+static bool save_complete_inventory(const char *path,
+ struct save_complete_entry *list);
/**
* Save an HTML page with all dependencies.
@@ -80,17 +84,18 @@ static bool save_complete_inventory(const char *path);
bool save_complete(struct content *c, const char *path)
{
bool result;
-
- result = save_complete_html(c, path, true);
+ struct save_complete_entry *list = NULL;
+
+ result = save_complete_html(c, path, true, &list);
if (result)
- result = save_complete_inventory(path);
+ result = save_complete_inventory(path, list);
/* free save_complete_list */
- while (save_complete_list) {
- struct save_complete_entry *next = save_complete_list->next;
- free(save_complete_list);
- save_complete_list = next;
+ while (list) {
+ struct save_complete_entry *next = list->next;
+ free(list);
+ list = next;
}
return result;
@@ -106,19 +111,20 @@ bool save_complete(struct content *c, const char *path)
* \return true on success, false on error and error reported
*/
-bool save_complete_html(struct content *c, const char *path, bool index)
+bool save_complete_html(struct content *c, const char *path, bool index,
+ struct save_complete_entry **list)
{
- char spath[256];
+ char filename[256];
unsigned int i;
xmlDocPtr doc;
- os_error *error;
+ bool res;
if (c->type != CONTENT_HTML)
return false;
- if (save_complete_list_check(c))
+ if (save_complete_list_check(c, *list))
return true;
-
+
/* save stylesheets, ignoring the base and adblocking sheets */
for (i = STYLESHEET_START; i != c->data.html.stylesheet_count; i++) {
struct content *css = c->data.html.stylesheets[i].c;
@@ -128,44 +134,39 @@ bool save_complete_html(struct content *c, const char *path, bool index)
if (!css)
continue;
- if (save_complete_list_check(css))
+ if (save_complete_list_check(css, *list))
continue;
is_style = (strcmp(css->url, c->data.html.base_url) == 0);
if (is_style == false) {
- if (!save_complete_list_add(css)) {
+ if (!save_complete_list_add(css, list)) {
warn_user("NoMemory", 0);
return false;
}
}
- if (!save_imported_sheets(css, path))
+ if (!save_imported_sheets(css, path, list))
return false;
if (is_style)
continue; /* don't save <style> elements */
- snprintf(spath, sizeof spath, "%s.%x", path,
- (unsigned int) css);
+ snprintf(filename, sizeof filename, "%p", css);
source = rewrite_stylesheet_urls(css->source_data,
- css->source_size, &source_len, css->url);
+ css->source_size, &source_len, css->url,
+ *list);
if (!source) {
warn_user("NoMemory", 0);
return false;
}
-
- error = xosfile_save_stamped(spath, 0xf79,
- (byte *) source, (byte *) source + source_len);
+ res = save_complete_gui_save(path, filename, source_len,
+ source, CONTENT_CSS);
free(source);
- if (error) {
- LOG(("xosfile_save_stamped: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
+ if (res == false)
return false;
- }
}
-
+
/* save objects */
for (i = 0; i != c->data.html.object_count; i++) {
struct content *obj = c->data.html.object[i].content;
@@ -173,32 +174,25 @@ bool save_complete_html(struct content *c, const char *path, bool index)
/* skip difficult content types */
if (!obj || obj->type >= CONTENT_OTHER || !obj->source_data)
continue;
- if (save_complete_list_check(obj))
+ if (save_complete_list_check(obj, *list))
continue;
- if (!save_complete_list_add(obj)) {
+ if (!save_complete_list_add(obj, list)) {
warn_user("NoMemory", 0);
return false;
}
if (obj->type == CONTENT_HTML) {
- if (!save_complete_html(obj, path, false))
+ if (!save_complete_html(obj, path, false, list))
return false;
continue;
}
- snprintf(spath, sizeof spath, "%s.%x", path,
- (unsigned int) obj);
- error = xosfile_save_stamped(spath,
- ro_content_filetype(obj),
- (byte *) obj->source_data,
- (byte *) obj->source_data + obj->source_size);
- if (error) {
- LOG(("xosfile_save_stamped: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
+ snprintf(filename, sizeof filename, "%p", obj);
+ res = save_complete_gui_save(path, filename,
+ obj->source_size, obj->source_data, obj->type);
+ if(res == false)
return false;
- }
}
/*save_complete_list_dump();*/
@@ -211,7 +205,7 @@ bool save_complete_html(struct content *c, const char *path, bool index)
}
/* rewrite all urls we know about */
- if (!rewrite_document_urls(doc, c->data.html.base_url)) {
+ if (!rewrite_document_urls(doc, c->data.html.base_url, *list)) {
xmlFreeDoc(doc);
warn_user("NoMemory", 0);
return false;
@@ -219,12 +213,12 @@ bool save_complete_html(struct content *c, const char *path, bool index)
/* save the html file out last of all */
if (index)
- snprintf(spath, sizeof spath, "%s.index", path);
- else
- snprintf(spath, sizeof spath, "%s.%x", path, (unsigned int)c);
+ snprintf(filename, sizeof filename, "index");
+ else
+ snprintf(filename, sizeof filename, "%p", c);
errno = 0;
- if (htmlSaveFileFormat(spath, doc, 0, 0) == -1) {
+ if (save_complete_htmlSaveFileFormat(path, filename, doc, 0, 0) == -1) {
if (errno)
warn_user("SaveError", strerror(errno));
else
@@ -232,18 +226,10 @@ bool save_complete_html(struct content *c, const char *path, bool index)
xmlFreeDoc(doc);
return false;
- }
+ }
xmlFreeDoc(doc);
- error = xosfile_set_type(spath, 0xfaf);
- if (error) {
- LOG(("xosfile_set_type: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
- return false;
- }
-
return true;
}
@@ -256,48 +242,45 @@ bool save_complete_html(struct content *c, const char *path, bool index)
* \return true on success, false on error and error reported
*/
-bool save_imported_sheets(struct content *c, const char *path)
+bool save_imported_sheets(struct content *c, const char *path,
+ struct save_complete_entry **list)
{
- char spath[256];
+ char filename[256];
unsigned int j;
char *source;
int source_len;
- os_error *error;
+ bool res;
for (j = 0; j != c->data.css.import_count; j++) {
struct content *css = c->data.css.imports[j].c;
if (!css)
continue;
- if (save_complete_list_check(css))
+ if (save_complete_list_check(css, *list))
continue;
- if (!save_complete_list_add(css)) {
+ if (!save_complete_list_add(css, list)) {
warn_user("NoMemory", 0);
return false;
}
- if (!save_imported_sheets(css, path))
+ if (!save_imported_sheets(css, path, list))
return false;
- snprintf(spath, sizeof spath, "%s.%x", path,
- (unsigned int) css);
+ snprintf(filename, sizeof filename, "%p", css);
source = rewrite_stylesheet_urls(css->source_data,
- css->source_size, &source_len, css->url);
+ css->source_size, &source_len, css->url,
+ *list);
if (!source) {
warn_user("NoMemory", 0);
return false;
}
- error = xosfile_save_stamped(spath, 0xf79,
- (byte *) source, (byte *) source + source_len);
+ res = save_complete_gui_save(path, filename, source_len,
+ source, CONTENT_CSS);
free(source);
- if (error) {
- LOG(("xosfile_save_stamped: 0x%x: %s",
- error->errnum, error->errmess));
- warn_user("SaveError", error->errmess);
+ if (res == false)
return false;
- }
}
return true;
@@ -352,7 +335,8 @@ void save_complete_init(void)
*/
char * rewrite_stylesheet_urls(const char *source, unsigned int size,
- int *osize, const char *base)
+ int *osize, const char *base,
+ struct save_complete_entry *list)
{
char *res;
const char *url;
@@ -435,11 +419,11 @@ char * rewrite_stylesheet_urls(const char *source, unsigned int size,
*osize += match[0].rm_so;
if (result == URL_FUNC_OK) {
- content = save_complete_list_find(url);
+ content = save_complete_list_find(url, list);
if (content) {
/* replace import */
- snprintf(buf, sizeof buf, "@import '%x'",
- (unsigned int) content);
+ snprintf(buf, sizeof buf, "@import '%p'",
+ content);
memcpy(res + *osize, buf, strlen(buf));
*osize += strlen(buf);
} else {
@@ -478,13 +462,14 @@ char * rewrite_stylesheet_urls(const char *source, unsigned int size,
* \return true on success, false on out of memory
*/
-bool rewrite_document_urls(xmlDoc *doc, const char *base)
+bool rewrite_document_urls(xmlDoc *doc, const char *base,
+ struct save_complete_entry *list)
{
xmlNode *node;
for (node = doc->children; node; node = node->next)
if (node->type == XML_ELEMENT_NODE)
- if (!rewrite_urls(node, base))
+ if (!rewrite_urls(node, base, list))
return false;
return true;
@@ -501,7 +486,8 @@ bool rewrite_document_urls(xmlDoc *doc, const char *base)
* URLs in the tree rooted at element n are rewritten.
*/
-bool rewrite_urls(xmlNode *n, const char *base)
+bool rewrite_urls(xmlNode *n, const char *base,
+ struct save_complete_entry *list)
{
xmlNode *child;
@@ -524,14 +510,14 @@ bool rewrite_urls(xmlNode *n, const char *base)
}
/* 1 */
else if (strcmp((const char *) n->name, "object") == 0) {
- if (!rewrite_url(n, "data", base))
+ if (!rewrite_url(n, "data", base, list))
return false;
}
/* 2 */
else if (strcmp((const char *) n->name, "a") == 0 ||
strcmp((const char *) n->name, "area") == 0 ||
strcmp((const char *) n->name, "link") == 0) {
- if (!rewrite_url(n, "href", base))
+ if (!rewrite_url(n, "href", base, list))
return false;
}
/* 3 */
@@ -540,7 +526,7 @@ bool rewrite_urls(xmlNode *n, const char *base)
strcmp((const char *) n->name, "input") == 0 ||
strcmp((const char *) n->name, "img") == 0 ||
strcmp((const char *) n->name, "script") == 0) {
- if (!rewrite_url(n, "src", base))
+ if (!rewrite_url(n, "src", base, list))
return false;
}
/* 4 */
@@ -561,7 +547,7 @@ bool rewrite_urls(xmlNode *n, const char *base)
char *rewritten = rewrite_stylesheet_urls(
(const char *) content,
strlen((const char *) content),
- (int *) &len, base);
+ (int *) &len, base, list);
xmlFree(content);
if (!rewritten)
return false;
@@ -586,7 +572,7 @@ bool rewrite_urls(xmlNode *n, const char *base)
}
/* 6 */
else {
- if (!rewrite_url(n, "background", base))
+ if (!rewrite_url(n, "background", base, list))
return false;
}
@@ -598,7 +584,7 @@ bool rewrite_urls(xmlNode *n, const char *base)
* next child */
xmlNode *next = child->next;
if (child->type == XML_ELEMENT_NODE) {
- if (!rewrite_urls(child, base))
+ if (!rewrite_urls(child, base, list))
return false;
}
child = next;
@@ -617,7 +603,8 @@ bool rewrite_urls(xmlNode *n, const char *base)
* \return true on success, false on out of memory
*/
-bool rewrite_url(xmlNode *n, const char *attr, const char *base)
+bool rewrite_url(xmlNode *n, const char *attr, const char *base,
+ struct save_complete_entry *list)
{
char *url, *data;
char rel[20];
@@ -636,12 +623,11 @@ bool rewrite_url(xmlNode *n, const char *attr, const char *base)
if (res == URL_FUNC_NOMEM)
return false;
else if (res == URL_FUNC_OK) {
- content = save_complete_list_find(url);
+ content = save_complete_list_find(url, list);
if (content) {
/* found a match */
free(url);
- snprintf(rel, sizeof rel, "%x",
- (unsigned int) content);
+ snprintf(rel, sizeof rel, "%p", content);
if (!xmlSetProp(n, (const xmlChar *) attr,
(xmlChar *) rel))
return false;
@@ -667,15 +653,16 @@ bool rewrite_url(xmlNode *n, const char *attr, const char *base)
* \return true on success, false on out of memory
*/
-bool save_complete_list_add(struct content *content)
+bool save_complete_list_add(struct content *content,
+ struct save_complete_entry **list)
{
struct save_complete_entry *entry;
entry = malloc(sizeof (*entry));
if (!entry)
return false;
entry->content = content;
- entry->next = save_complete_list;
- save_complete_list = entry;
+ entry->next = *list;
+ *list = entry;
return true;
}
@@ -687,10 +674,11 @@ bool save_complete_list_add(struct content *content)
* \return content if found, 0 otherwise
*/
-struct content * save_complete_list_find(const char *url)
+struct content * save_complete_list_find(const char *url,
+ struct save_complete_entry *list)
{
struct save_complete_entry *entry;
- for (entry = save_complete_list; entry; entry = entry->next)
+ for (entry = list; entry; entry = entry->next)
if (strcmp(url, entry->content->url) == 0)
return entry->content;
return 0;
@@ -704,10 +692,11 @@ struct content * save_complete_list_find(const char *url)
* \return true if the content is in the save_complete_list
*/
-bool save_complete_list_check(struct content *content)
+bool save_complete_list_check(struct content *content,
+ struct save_complete_entry *list)
{
struct save_complete_entry *entry;
- for (entry = save_complete_list; entry; entry = entry->next)
+ for (entry = list; entry; entry = entry->next)
if (entry->content == content)
return true;
return false;
@@ -732,14 +721,23 @@ void save_complete_list_dump(void)
* Create the inventory file listing original URLs.
*/
-bool save_complete_inventory(const char *path)
+bool save_complete_inventory(const char *path,
+ struct save_complete_entry *list)
{
- char spath[256];
+ char urlpath[256];
FILE *fp;
+ char *pathstring, *standardpath = (path[0] == '/') ?
+ (char *)(path + 1) : (char *)path;
- snprintf(spath, sizeof spath, "%s.Inventory", path);
-
- fp = fopen(spath, "w");
+ snprintf(urlpath, sizeof urlpath, "file:///%s/Inventory",
+ standardpath);
+ pathstring = url_to_path(urlpath);
+ if (pathstring == NULL) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ fp = fopen(pathstring, "w");
+ free(pathstring);
if (!fp) {
LOG(("fopen(): errno = %i", errno));
warn_user("SaveError", strerror(errno));
@@ -747,10 +745,8 @@ bool save_complete_inventory(const char *path)
}
struct save_complete_entry *entry;
- for (entry = save_complete_list; entry; entry = entry->next)
- fprintf(fp, "%x %s\n",
- (unsigned int) entry->content,
- entry->content->url);
+ for (entry = list; entry; entry = entry->next)
+ fprintf(fp, "%p %s\n", entry->content, entry->content->url);
fclose(fp);
diff --git a/desktop/save_complete.h b/desktop/save_complete.h
new file mode 100644
index 000000000..e23092471
--- /dev/null
+++ b/desktop/save_complete.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Save HTML document with dependencies (interface).
+ */
+
+#ifndef _NETSURF_DESKTOP_SAVE_COMPLETE_H_
+#define _NETSURF_DESKTOP_SAVE_COMPLETE_H_
+
+#include <stdbool.h>
+#include <libxml/HTMLtree.h>
+#include "content/content.h"
+
+struct content;
+
+void save_complete_init(void);
+bool save_complete(struct content *c, const char *path);
+
+bool save_complete_gui_save(const char *path, const char *filename,
+ size_t len, const char *sourcedata, content_type type);
+
+int save_complete_htmlSaveFileFormat(const char *path, const char *filename,
+ xmlDocPtr cur, const char *encoding, int format);
+
+#endif
diff --git a/desktop/search.c b/desktop/search.c
new file mode 100644
index 000000000..018f40674
--- /dev/null
+++ b/desktop/search.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+ /** \file
+ * Free text search (core)
+ */
+#include "utils/config.h"
+
+#include <ctype.h>
+#include <string.h>
+#include "content/content.h"
+#include "desktop/browser.h"
+#include "desktop/gui.h"
+#include "desktop/options.h"
+#include "desktop/search.h"
+#include "desktop/selection.h"
+#include "render/box.h"
+#include "render/html.h"
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+
+#ifndef NOF_ELEMENTS
+#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
+#endif
+
+
+struct list_entry {
+ unsigned start_idx; /* start position of match */
+ unsigned end_idx; /* end of match */
+
+ struct box *start_box; /* used only for html contents */
+ struct box *end_box;
+
+ struct selection *sel;
+
+ struct list_entry *prev;
+ struct list_entry *next;
+};
+
+struct search_context {
+ struct browser_window *bw;
+ struct content *content;
+ char *string;
+ bool prev_case_sens;
+ bool newsearch;
+ bool insert;
+ void *p; /* front-specific data */
+ struct search_callbacks *callbacks;
+ struct list_entry *found;
+ struct list_entry *current; /* first for select all */
+};
+
+static void search_text(const char *string, int string_len,
+ struct search_context *context, search_flags_t flags);
+static const char *find_pattern(const char *string, int s_len,
+ const char *pattern, int p_len, bool case_sens,
+ unsigned int *m_len);
+static bool find_occurrences_html(const char *pattern, int p_len,
+ struct box *cur, bool case_sens,
+ struct search_context *context);
+static bool find_occurrences_text(const char *pattern, int p_len,
+ struct content *c, bool case_sens,
+ struct search_context *context);
+static struct list_entry *add_entry(unsigned start_idx, unsigned end_idx,
+ struct search_context *context);
+static void free_matches(struct search_context *context);
+
+
+/**
+ * create a search_context
+ * \param bw the browser_window the search_context is connected to
+ * \param callbacks the callbacks to modify appearance according to results
+ * \param p the pointer to send to the callbacks
+ * \return true for success
+ */
+bool search_create_context(struct browser_window *bw,
+ struct search_callbacks *callbacks, void *p)
+{
+ struct search_context *context = malloc(sizeof(struct search_context));
+ struct list_entry *search_head = malloc(sizeof(struct list_entry));
+
+ if ((context == NULL) || (search_head == NULL)) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ if (bw->search_context != NULL)
+ search_destroy_context(bw->search_context);
+
+ search_head->start_idx = 0;
+ search_head->end_idx = 0;
+ search_head->start_box = NULL;
+ search_head->end_box = NULL;
+ search_head->sel = NULL;
+ search_head->prev = NULL;
+ search_head->next = NULL;
+
+ context->found = search_head;
+ context->current = NULL;
+ context->content = NULL;
+ context->string = NULL;
+ context->prev_case_sens = false;
+ context->newsearch = true;
+ context->insert = true;
+ context->bw = bw;
+ context->callbacks = callbacks;
+ context->p = p;
+
+ bw->search_context = context;
+ return true;
+}
+/**
+ * to simplify calls to search_step(); checks that the browser_window is
+ * non-NULL, creates a new search_context in case of a new search
+ * \param bw the browser_window the search refers to
+ * \param callbacks the callbacks to modify appearance according to results
+ * \param p a pointer returned to the callbacks
+ * \return true for success
+ */
+bool search_verify_new(struct browser_window *bw,
+ struct search_callbacks *callbacks, void *p)
+{
+ if (bw == NULL)
+ return false;
+ if (bw->search_context == NULL)
+ return search_create_context(bw, callbacks, p);
+ return true;
+}
+
+/**
+ * Begins/continues the search process
+ * Note that this may be called many times for a single search.
+ *
+ * \param bw the browser_window to search in
+ * \param flags the flags forward/back etc
+ * \param string the string to match
+ */
+
+void search_step(struct search_context *context, search_flags_t flags,
+ const char *string)
+{
+ int string_len;
+ int i = 0;
+
+ if ((context == NULL) || (context->callbacks == NULL)) {
+ warn_user("SearchError", 0);
+ return;
+ }
+
+
+ if (context->callbacks->add_recent != NULL)
+ context->callbacks->add_recent(string, context->p);
+
+ string_len = strlen(string);
+ for(i = 0; i < string_len; i++)
+ if (string[i] != '#' && string[i] != '*') break;
+ if (i >= string_len) {
+ free_matches(context);
+ if (context->callbacks->status != NULL)
+ context->callbacks->status(true, context->p);
+ if (context->callbacks->back_state != NULL)
+ context->callbacks->back_state(false, context->p);
+ if (context->callbacks->forward_state != NULL)
+ context->callbacks->forward_state(false, context->p);
+ gui_window_set_scroll(context->bw->window, 0, 0);
+ return;
+ }
+ search_text(string, string_len, context, flags);
+}
+
+/**
+ * Release the memory used by the list of matches,
+ * deleting selection objects too
+ */
+
+void free_matches(struct search_context *context)
+{
+ struct list_entry *a = context->found->next;
+ struct list_entry *b;
+
+ /* empty the list before clearing and deleting the
+ selections because the the clearing updates the
+ screen immediately, causing nested accesses to the list */
+
+ context->found->prev = NULL;
+ context->found->next = NULL;
+
+ for (; a; a = b) {
+ b = a->next;
+ if (a->sel) {
+ selection_clear(a->sel, true);
+ selection_destroy(a->sel);
+ }
+ free(a);
+ }
+}
+
+/**
+ * Search for a string in the box tree
+ *
+ * \param string the string to search for
+ * \param string_len length of search string
+ */
+void search_text(const char *string, int string_len,
+ struct search_context *context, search_flags_t flags)
+{
+ struct rect bounds;
+ struct content *c;
+ struct box *box;
+ bool case_sensitive, forwards, showall;
+
+ case_sensitive = ((flags & SEARCH_FLAG_CASE_SENSITIVE) != 0) ?
+ true : false;
+ forwards = ((flags & SEARCH_FLAG_FORWARDS) != 0) ? true : false;
+ showall = ((flags & SEARCH_FLAG_SHOWALL) != 0) ? true : false;
+
+ if (context->bw == NULL)
+ return;
+ c = context->bw->current_content;
+
+ /* only handle html contents */
+ if ((!c) || (c->type != CONTENT_HTML &&
+ c->type != CONTENT_TEXTPLAIN))
+ return;
+
+ box = c->data.html.layout;
+
+ if (!box)
+ return;
+
+ /* LOG(("do_search '%s' - '%s' (%p, %p) %p (%d, %d) %d",
+ search_data.string, string, search_data.content, c, search_data.found->next,
+ search_data.prev_case_sens, case_sens, forwards)); */
+
+ /* check if we need to start a new search or continue an old one */
+ if (context->newsearch) {
+ bool res;
+
+ if (context->string != NULL)
+ free(context->string);
+ context->current = NULL;
+ free_matches(context);
+
+ context->string = malloc(string_len + 1);
+ if (context->string != NULL) {
+ memcpy(context->string, string, string_len);
+ context->string[string_len] = '\0';
+ }
+
+ if ((context->callbacks != NULL) &&
+ (context->callbacks->hourglass != NULL))
+ context->callbacks->hourglass(true, context->p);
+
+ if (c->type == CONTENT_HTML)
+ res = find_occurrences_html(string, string_len,
+ box, case_sensitive, context);
+ else {
+ assert(c->type == CONTENT_TEXTPLAIN);
+ res = find_occurrences_text(string, string_len,
+ c, case_sensitive, context);
+ }
+
+ if (!res) {
+ free_matches(context);
+ if ((context->callbacks != NULL) &&
+ (context->callbacks->hourglass !=
+ NULL))
+ context->callbacks->hourglass(false,
+ context->p);
+ return;
+ }
+ if ((context->callbacks != NULL) &&
+ (context->callbacks->hourglass != NULL))
+ context->callbacks->hourglass(false, context->p);
+
+ context->content = c;
+ context->prev_case_sens = case_sensitive;
+/* LOG(("%d %p %p (%p, %p)", new, search_data.found->next, search_data.current,
+ search_data.current->prev, search_data.current->next)); */
+ /* new search, beginning at the top of the page */
+ context->current = context->found->next;
+ context->newsearch = false;
+ }
+ else if (context->current != NULL) {
+ /* continued search in the direction specified */
+ if (forwards) {
+ if (context->current->next)
+ context->current = context->current->next;
+ }
+ else {
+ if (context->current->prev)
+ context->current = context->current->prev;
+ }
+ }
+
+ if (context->callbacks == NULL)
+ return;
+ if (context->callbacks->status != NULL)
+ context->callbacks->status((context->current != NULL),
+ context->p);
+ search_show_all(showall, context);
+
+ if (context->callbacks->back_state != NULL)
+ context->callbacks->back_state((context->current != NULL) &&
+ (context->current->prev != NULL),
+ context->p);
+ if (context->callbacks->forward_state != NULL)
+ context->callbacks->forward_state((context->current != NULL) &&
+ (context->current->next != NULL), context->p);
+
+ if (context->current == NULL)
+ return;
+
+ switch (c->type) {
+ case CONTENT_HTML:
+ /* get box position and jump to it */
+ box_coords(context->current->start_box,
+ &bounds.x0, &bounds.y0);
+ /* \todo: move x0 in by correct idx */
+ box_coords(context->current->end_box,
+ &bounds.x1, &bounds.y1);
+ /* \todo: move x1 in by correct idx */
+ bounds.x1 += context->current->end_box->width;
+ bounds.y1 += context->current->end_box->height;
+ break;
+
+ default:
+ assert(c->type == CONTENT_TEXTPLAIN);
+ textplain_coords_from_range(c,
+ context->current->start_idx,
+ context->current->end_idx, &bounds);
+ break;
+ }
+
+ gui_window_scroll_visible(context->bw->window,
+ bounds.x0, bounds.y0, bounds.x1, bounds.y1);
+}
+
+/**
+ * Find the first occurrence of 'match' in 'string' and return its index
+ *
+ * \param string the string to be searched (unterminated)
+ * \param s_len length of the string to be searched
+ * \param pattern the pattern for which we are searching (unterminated)
+ * \param p_len length of pattern
+ * \param case_sens true iff case sensitive match required
+ * \param m_len accepts length of match in bytes
+ * \return pointer to first match, NULL if none
+ */
+
+const char *find_pattern(const char *string, int s_len, const char *pattern,
+ int p_len, bool case_sens, unsigned int *m_len)
+{
+ struct { const char *ss, *s, *p; bool first; } context[16];
+ const char *ep = pattern + p_len;
+ const char *es = string + s_len;
+ const char *p = pattern - 1; /* a virtual '*' before the pattern */
+ const char *ss = string;
+ const char *s = string;
+ bool first = true;
+ int top = 0;
+
+ while (p < ep) {
+ bool matches;
+ if (p < pattern || *p == '*') {
+ char ch;
+
+ /* skip any further asterisks; one is the same as many
+ */
+ do p++; while (p < ep && *p == '*');
+
+ /* if we're at the end of the pattern, yes, it matches
+ */
+ if (p >= ep) break;
+
+ /* anything matches a # so continue matching from
+ here, and stack a context that will try to match
+ the wildcard against the next character */
+
+ ch = *p;
+ if (ch != '#') {
+ /* scan forwards until we find a match for
+ this char */
+ if (!case_sens) ch = toupper(ch);
+ while (s < es) {
+ if (case_sens) {
+ if (*s == ch) break;
+ } else if (toupper(*s) == ch)
+ break;
+ s++;
+ }
+ }
+
+ if (s < es) {
+ /* remember where we are in case the match
+ fails; we may then resume */
+ if (top < (int)NOF_ELEMENTS(context)) {
+ context[top].ss = ss;
+ context[top].s = s + 1;
+ context[top].p = p - 1;
+ /* ptr to last asterisk */
+ context[top].first = first;
+ top++;
+ }
+
+ if (first) {
+ ss = s;
+ /* remember first non-'*' char */
+ first = false;
+ }
+
+ matches = true;
+ }
+ else
+ matches = false;
+ }
+ else if (s < es) {
+ char ch = *p;
+ if (ch == '#')
+ matches = true;
+ else {
+ if (case_sens)
+ matches = (*s == ch);
+ else
+ matches = (toupper(*s) == toupper(ch));
+ }
+ if (matches && first) {
+ ss = s; /* remember first non-'*' char */
+ first = false;
+ }
+ }
+ else
+ matches = false;
+
+ if (matches) {
+ p++; s++;
+ }
+ else {
+ /* doesn't match, resume with stacked context if we have one */
+ if (--top < 0) return NULL; /* no match, give up */
+
+ ss = context[top].ss;
+ s = context[top].s;
+ p = context[top].p;
+ first = context[top].first;
+ }
+ }
+
+ /* end of pattern reached */
+ *m_len = max(s - ss, 1);
+ return ss;
+}
+
+/**
+ * Finds all occurrences of a given string in the html box tree
+ *
+ * \param pattern the string pattern to search for
+ * \param p_len pattern length
+ * \param cur pointer to the current box
+ * \param case_sens whether to perform a case sensitive search
+ * \return true on success, false on memory allocation failure
+ */
+bool find_occurrences_html(const char *pattern, int p_len, struct box *cur,
+ bool case_sens, struct search_context *context)
+{
+ struct box *a;
+
+ /* ignore this box, if there's no visible text */
+ if (!cur->object && cur->text) {
+ const char *text = cur->text;
+ unsigned length = cur->length;
+
+ while (length > 0) {
+ struct list_entry *entry;
+ unsigned match_length;
+ unsigned match_offset;
+ const char *new_text;
+ const char *pos = find_pattern(text, length,
+ pattern, p_len, case_sens,
+ &match_length);
+ if (!pos) break;
+
+ /* found string in box => add to list */
+ match_offset = pos - cur->text;
+
+ entry = add_entry(cur->byte_offset + match_offset,
+ cur->byte_offset +
+ match_offset +
+ match_length, context);
+ if (!entry)
+ return false;
+
+ entry->start_box = cur;
+ entry->end_box = cur;
+
+ new_text = pos + match_length;
+ length -= (new_text - text);
+ text = new_text;
+ }
+ }
+
+ /* and recurse */
+ for (a = cur->children; a; a = a->next) {
+ if (!find_occurrences_html(pattern, p_len, a, case_sens,
+ context))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Finds all occurrences of a given string in a textplain content
+ *
+ * \param pattern the string pattern to search for
+ * \param p_len pattern length
+ * \param c the content to be searched
+ * \param case_sens wheteher to perform a case sensitive search
+ * \return true on success, false on memory allocation failure
+ */
+
+bool find_occurrences_text(const char *pattern, int p_len,
+ struct content *c, bool case_sens,
+ struct search_context *context)
+{
+ int nlines = textplain_line_count(c);
+ int line;
+
+ for(line = 0; line < nlines; line++) {
+ size_t offset, length;
+ const char *text = textplain_get_line(c, line,
+ &offset, &length);
+ if (text) {
+ while (length > 0) {
+ struct list_entry *entry;
+ unsigned match_length;
+ size_t start_idx;
+ const char *new_text;
+ const char *pos = find_pattern(text, length,
+ pattern, p_len, case_sens,
+ &match_length);
+ if (!pos) break;
+
+ /* found string in line => add to list */
+ start_idx = offset + (pos - text);
+ entry = add_entry(start_idx, start_idx +
+ match_length, context);
+ if (!entry)
+ return false;
+
+ new_text = pos + match_length;
+ offset += (new_text - text);
+ length -= (new_text - text);
+ text = new_text;
+ }
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Determines whether any portion of the given text box should be
+ * selected because it matches the current search string.
+ *
+ * \param g gui window
+ * \param start_offset byte offset within text of string to be checked
+ * \param end_offset byte offset within text
+ * \param start_idx byte offset within string of highlight start
+ * \param end_idx byte offset of highlight end
+ * \return true iff part of the box should be highlighted
+ */
+
+bool gui_search_term_highlighted(struct gui_window *g,
+ unsigned start_offset, unsigned end_offset,
+ unsigned *start_idx, unsigned *end_idx,
+ struct search_context *context)
+{
+ if (g == context->bw->window) {
+ struct list_entry *a;
+ for(a = context->found->next; a; a = a->next)
+ if (a->sel && selection_defined(a->sel) &&
+ selection_highlighted(a->sel,
+ start_offset, end_offset,
+ start_idx, end_idx))
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Specifies whether all matches or just the current match should
+ * be highlighted in the search text.
+ */
+
+void search_show_all(bool all, struct search_context *context)
+{
+ struct list_entry *a;
+
+ for (a = context->found->next; a; a = a->next) {
+ bool add = true;
+ if (!all && a != context->current) {
+ add = false;
+ if (a->sel) {
+ selection_clear(a->sel, true);
+ selection_destroy(a->sel);
+ a->sel = NULL;
+ }
+ }
+ if (add && !a->sel) {
+ a->sel = selection_create(context->bw);
+ if (a->sel) {
+ struct content *c = context->bw->
+ current_content;
+ switch (c->type) {
+ case CONTENT_HTML:
+ selection_init(a->sel,
+ c->data.html.layout);
+ break;
+ default:
+ assert(c->type ==
+ CONTENT_TEXTPLAIN);
+ selection_init(a->sel, NULL);
+ break;
+ }
+ selection_set_start(a->sel, a->start_idx);
+ selection_set_end(a->sel, a->end_idx);
+ }
+ }
+ }
+}
+
+/**
+ * Add a new entry to the list of matches
+ *
+ * \param start_idx offset of match start within textual representation
+ * \param end_idx offset of match end
+ * \return pointer to added entry, NULL iff failed
+ */
+
+struct list_entry *add_entry(unsigned start_idx, unsigned end_idx,
+ struct search_context *context)
+{
+ struct list_entry *entry;
+
+ /* found string in box => add to list */
+ entry = calloc(1, sizeof(*entry));
+ if (!entry) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ entry->start_idx = start_idx;
+ entry->end_idx = end_idx;
+ entry->sel = NULL;
+
+ entry->next = 0;
+ entry->prev = context->found->prev;
+ if (context->found->prev == NULL)
+ context->found->next = entry;
+ else
+ context->found->prev->next = entry;
+ context->found->prev = entry;
+
+ return entry;
+}
+
+/**
+ * Ends the search process, invalidating all state
+ * freeing the list of found boxes
+ */
+void search_destroy_context(struct search_context *context)
+{
+ if (context->bw != NULL)
+ context->bw->search_context = NULL;
+ if ((context->string != NULL) && (context->callbacks != NULL) &&
+ (context->callbacks->add_recent != NULL)) {
+ context->callbacks->add_recent(context->string, context->p);
+ free(context->string);
+ }
+ free_matches(context);
+ free(context);
+}
+
diff --git a/desktop/search.h b/desktop/search.h
new file mode 100644
index 000000000..15a4f6c9e
--- /dev/null
+++ b/desktop/search.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_DESKTOP_SEARCH_H_
+#define _NETSURF_DESKTOP_SEARCH_H_
+
+#include <ctype.h>
+#include <string.h>
+
+struct search_context;
+
+typedef enum {
+ SEARCH_FLAG_CASE_SENSITIVE = (1 << 0),
+ SEARCH_FLAG_FORWARDS = (1 << 1),
+ SEARCH_FLAG_SHOWALL = (1 << 2)
+} search_flags_t;
+
+/**
+ * called to clear the context; 'renews' the search too
+ */
+void search_destroy_context(struct search_context *context);
+
+/**
+ * Change the displayed search status.
+ * \param found search pattern matched in text
+ * \param p the pointer sent to search_step() / search_create_context()
+ */
+typedef void (*search_status_callback)(bool found, void *p);
+
+/**
+ * display hourglass while searching
+ * \param active start/stop indicator
+ * \param p the pointer sent to search_step() / search_create_context()
+ */
+typedef void (*search_hourglass_callback)(bool active, void *p);
+
+/**
+ * add search string to recent searches list
+ * front has full liberty how to implement the bare notification;
+ * core gives no guarantee of the integrity of the const char *
+ * \param string search pattern
+ * \param p the pointer sent to search_step() / search_create_context()
+ */
+typedef void (*search_add_recent_callback)(const char *string, void *p);
+
+/**
+ * activate search forwards button in gui
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_step() / search_create_context()
+ */
+typedef void (*search_forward_state_callback)(bool active, void *p);
+
+/**
+ * activate search back button in gui
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_step() / search_create_context()
+ */
+typedef void (*search_back_state_callback)(bool active, void *p);
+
+struct search_callbacks {
+ search_forward_state_callback forward_state;
+ search_back_state_callback back_state;
+ search_status_callback status;
+ search_hourglass_callback hourglass;
+ search_add_recent_callback add_recent;
+};
+
+bool search_verify_new(struct browser_window *bw,
+ struct search_callbacks *callbacks, void *p);
+void search_step(struct search_context *context, search_flags_t flags,
+ const char * string);
+bool search_create_context(struct browser_window *bw,
+ struct search_callbacks *callbacks, void *p);
+void search_show_all(bool all, struct search_context *context);
+
+#endif
diff --git a/desktop/searchweb.c b/desktop/searchweb.c
new file mode 100644
index 000000000..c6dfaa6df
--- /dev/null
+++ b/desktop/searchweb.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+ /** \file
+ * web search (core)
+ */
+#include "utils/config.h"
+
+#include <ctype.h>
+#include <string.h>
+#include "content/content.h"
+#include "content/fetchcache.h"
+#include "content/fetch.h"
+#include "desktop/browser.h"
+#include "desktop/gui.h"
+#include "desktop/options.h"
+#include "desktop/searchweb.h"
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+static struct search_provider {
+ char *name; /**< readable name such as 'google', 'yahoo', etc */
+ char *hostname; /**< host address such as www.google.com */
+ char *searchstring; /** < such as "www.google.com?search=%s" */
+ char *ico; /** < location of domain's favicon */
+} current_search_provider;
+
+static struct content *search_ico = NULL;
+char *search_engines_file_location;
+char *search_default_ico_location;
+
+/**
+ * creates a new browser window according to the search term
+ * \param searchterm such as "my search term"
+ */
+
+bool search_web_new_window(struct browser_window *bw, const char *searchterm)
+{
+ char *encsearchterm;
+ char *url;
+ if (url_escape(searchterm,0, true, NULL, &encsearchterm) !=
+ URL_FUNC_OK)
+ return false;
+ url = search_web_get_url(encsearchterm);
+ free(encsearchterm);
+ browser_window_create(url, bw, NULL, false, true);
+ free(url);
+ return true;
+}
+
+/** simplistic way of checking whether an entry from the url bar is an
+ * url / a search; could be improved to properly test terms
+ */
+
+bool search_is_url(const char *url)
+{
+ char *url2, *host;
+
+ if (url_normalize(url, &url2) != URL_FUNC_OK)
+ return false;
+
+ if (url_host(url2, &host) != URL_FUNC_OK)
+ return false;
+
+ return true;
+}
+
+/**
+ * caches the details of the current web search provider
+ * \param reference the enum value of the provider
+ * browser init code [as well as changing preferences code] should call
+ * search_web_provider_details(option_search_provider)
+ */
+
+void search_web_provider_details(int reference)
+{
+ char buf[300];
+ int ref = 0;
+ if (search_engines_file_location == NULL)
+ return;
+ FILE *f = fopen(search_engines_file_location, "r");
+ if (f == NULL)
+ return;
+ while (fgets(buf, sizeof(buf), f) != NULL) {
+ if (buf[0] == '\0')
+ continue;
+ buf[strlen(buf)-1] = '\0';
+ if (ref++ == (int)reference)
+ break;
+ }
+ if (current_search_provider.name != NULL)
+ free(current_search_provider.name);
+ current_search_provider.name = strdup(strtok(buf, "|"));
+ if (current_search_provider.hostname != NULL)
+ free(current_search_provider.hostname);
+ current_search_provider.hostname = strdup(strtok(NULL, "|"));
+ if (current_search_provider.searchstring != NULL)
+ free(current_search_provider.searchstring);
+ current_search_provider.searchstring = strdup(strtok(NULL, "|"));
+ if (current_search_provider.ico != NULL)
+ free(current_search_provider.ico);
+ current_search_provider.ico = strdup(strtok(NULL, "|"));
+ return;
+}
+
+/**
+ * escapes a search term then creates the appropriate url from it
+ */
+
+char *search_web_from_term(const char *searchterm)
+{
+ char *encsearchterm, *url;
+ if (url_escape(searchterm, 0, true, NULL, &encsearchterm)
+ != URL_FUNC_OK)
+ return strdup(searchterm);
+ url = search_web_get_url(encsearchterm);
+ free(encsearchterm);
+ return url;
+}
+
+/** accessor for global search provider name */
+
+char *search_web_provider_name(void)
+{
+ if (current_search_provider.name)
+ return strdup(current_search_provider.name);
+ return strdup("google");
+}
+
+/** accessor for global search provider hostname */
+
+char *search_web_provider_host(void)
+{
+ if (current_search_provider.hostname)
+ return strdup(current_search_provider.hostname);
+ return strdup("www.google.com");
+}
+
+/** accessor for global search provider ico name */
+
+char *search_web_ico_name(void)
+{
+ if (current_search_provider.ico)
+ return strdup(current_search_provider.ico);
+ return strdup("http://www.google.com/favicon.ico");
+}
+
+/**
+ * creates a full url from an encoded search term
+ */
+
+char *search_web_get_url(const char *encsearchterm)
+{
+ char *pref, *ret;
+ int len;
+ if (current_search_provider.searchstring)
+ pref = strdup(current_search_provider.searchstring);
+ else
+ pref = strdup("http://www.google.com/search?q=%s");
+ if (pref == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ len = strlen(encsearchterm) + strlen(pref);
+ ret = malloc(len -1); /* + '\0' - "%s" */
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(pref);
+ return NULL;
+ }
+ snprintf(ret, len-1, pref, encsearchterm);
+ free(pref);
+ return ret;
+}
+
+/**
+ * function to retrieve the search web ico, from cache / from local
+ * filesystem / from the web
+ * \param localdefault true when there is no appropriate favicon
+ * update the search_ico cache else delay until fetcher callback
+ */
+
+void search_web_retrieve_ico(bool localdefault)
+{
+ char *url;
+ if (localdefault) {
+ if (search_default_ico_location == NULL)
+ return;
+ url = malloc(SLEN("file://") + strlen(
+ search_default_ico_location) + 1);
+ if (url == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ strcpy(url, "file://");
+ strcat(url, search_default_ico_location);
+ } else {
+ url = search_web_ico_name();
+ }
+
+ struct content *icocontent = NULL;
+ if (url == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ icocontent = fetchcache(url, search_web_ico_callback,
+ 0, 0, 20, 20, true, 0,
+ 0, false, false);
+ free(url);
+ if (icocontent == NULL)
+ return;
+
+ fetchcache_go(icocontent, 0, search_web_ico_callback,
+ 0, 0, 20, 20,
+ 0, 0, false, 0);
+
+ if (icocontent == NULL)
+ LOG(("web search ico loading delayed"));
+ else
+ search_ico = icocontent;
+}
+
+/**
+ * returns a reference to the static global search_ico [ / NULL]
+ * caller may adjust ico's settings; clearing / free()ing is the core's
+ * responsibility
+ */
+
+struct content *search_web_ico(void)
+{
+ return search_ico;
+}
+
+/**
+ * callback function to cache ico then notify front when successful
+ * else retry default from local file system
+ */
+
+void search_web_ico_callback(content_msg msg, struct content *ico,
+ intptr_t p1, intptr_t p2, union content_msg_data data)
+{
+
+ switch (msg) {
+ case CONTENT_MSG_LOADING:
+ case CONTENT_MSG_READY:
+ break;
+
+ case CONTENT_MSG_DONE:
+ LOG(("got favicon '%s'", ico->url));
+ if (ico->type == CONTENT_ICO) {
+ search_ico = ico; /* cache */
+ gui_window_set_search_ico(search_ico);
+ } else {
+ search_web_retrieve_ico(true);
+ }
+ break;
+
+ case CONTENT_MSG_LAUNCH:
+ case CONTENT_MSG_ERROR:
+ LOG(("favicon %s error: %s", ico->url, data.error));
+ ico = 0;
+ search_web_retrieve_ico(true);
+ break;
+
+ case CONTENT_MSG_STATUS:
+ case CONTENT_MSG_NEWPTR:
+ case CONTENT_MSG_AUTH:
+ case CONTENT_MSG_SSL:
+ break;
+
+ default:
+ assert(0);
+ }
+}
diff --git a/desktop/searchweb.h b/desktop/searchweb.h
new file mode 100644
index 000000000..f8dcb9db0
--- /dev/null
+++ b/desktop/searchweb.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_DESKTOP_SEARCH_WEB_H_
+#define _NETSURF_DESKTOP_SEARCH_WEB_H_
+
+#include <ctype.h>
+#include <string.h>
+#include "content/content.h"
+#include "desktop/browser.h"
+
+extern char *search_engines_file_location;
+extern char *search_default_ico_location;
+
+/**
+ * open new tab/window for web search term
+ */
+bool search_web_new_window(struct browser_window *bw, const char *searchterm);
+
+/**
+ * retrieve full search url from unencoded search term
+ */
+char *search_web_from_term(const char *searchterm);
+
+/**
+ * retrieve full search url from encoded web search term
+ */
+char *search_web_get_url(const char *encsearchterm);
+
+/**
+ * cache details of web search provider from file
+ */
+void search_web_provider_details(int reference);
+
+/**
+ * retrieve name of web search provider
+ */
+char *search_web_provider_name(void);
+
+/**
+ * retrieve hostname of web search provider
+ */
+char *search_web_provider_host(void);
+
+/**
+ * retrieve name of .ico for search bar
+ */
+char *search_web_ico_name(void);
+
+/**
+ * check whether an URL is in fact a search term
+ * \param url the url being checked
+ * \return true for url, false for search
+ */
+bool search_is_url(const char *url);
+
+void search_web_retrieve_ico(bool localdefault);
+
+struct content *search_web_ico(void);
+
+void search_web_ico_callback(content_msg msg, struct content *ico,
+ intptr_t p1, intptr_t p2, union content_msg_data data);
+
+#endif
diff --git a/framebuffer/fb_search.c b/framebuffer/fb_search.c
new file mode 100644
index 000000000..19fefa8b2
--- /dev/null
+++ b/framebuffer/fb_search.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include "utils/log.h"
+
+/* callback functions for search implementation */
+static void gui_search_set_status(bool found, void *p);
+static void gui_search_set_hourglass(bool active, void *p);
+static void gui_search_add_recent(const char *string, void *p);
+static void gui_search_set_forward_state(bool active, void *p);
+static void gui_search_set_back_state(bool active, void *p);
+
+/**
+* Change the displayed search status.
+* \param found search pattern matched in text
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+void gui_search_set_status(bool found, void *p)
+{
+}
+
+/**
+* display hourglass while searching
+* \param active start/stop indicator
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+void gui_search_set_hourglass(bool active, void *p)
+{
+}
+
+/**
+* add search string to recent searches list
+* \param string search pattern
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+void gui_search_add_recent(const char *string, void *p)
+{
+}
+
+/**
+* activate search forwards button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+void gui_search_set_forward_state(bool active, void *p)
+{
+}
+
+/**
+* activate search forwards button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+void gui_search_set_back_state(bool active, void *p)
+{
+}
diff --git a/gtk/dialogs/gtk_about.c b/gtk/dialogs/gtk_about.c
index da97195c7..2862f9f03 100644
--- a/gtk/dialogs/gtk_about.c
+++ b/gtk/dialogs/gtk_about.c
@@ -30,8 +30,9 @@ static const gchar *authors[] = {
"Matthew Hambley", "Rob Jackson", "Jeffrey Lee", "Phil Mellor",
"Philip Pemberton", "Darren Salt", "Andrew Timmins",
"John Tytgat", "Chris Williams",
- "\nGoogle Summer of Code Contributors:", "Adam Blokus",
- "Sean Fox", "Michael Lester", "Andrew Sidwell", NULL
+ "\nGoogle Summer of Code Contributors:", "Mark Benjamin",
+ "Adam Blokus", "Paul Blokus", "Sean Fox",
+ "Michael Lester", "Andrew Sidwell", "Bo Yang", NULL
};
static const gchar *translators = "Sebastian Barthel\nBruno D'Arcangeli\n"
diff --git a/gtk/dialogs/gtk_options.c b/gtk/dialogs/gtk_options.c
index 472b8c58d..00f73e97e 100644
--- a/gtk/dialogs/gtk_options.c
+++ b/gtk/dialogs/gtk_options.c
@@ -2,6 +2,7 @@
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
* Copyright 2008 Mike Lester <element3260@gmail.com>
* Copyright 2009 Daniel Silverstone <dsilvers@netsurf-browser.org>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -27,17 +28,20 @@
#include <glade/glade.h>
#include "desktop/options.h"
#include "desktop/print.h"
+#include "desktop/searchweb.h"
#include "gtk/options.h"
#include "gtk/gtk_gui.h"
#include "gtk/gtk_scaffolding.h"
+#include "gtk/gtk_theme.h"
#include "gtk/dialogs/gtk_options.h"
#include "gtk/gtk_window.h"
#include "utils/log.h"
#include "utils/utils.h"
+#include "utils/messages.h"
-GtkDialog *wndPreferences;
+GtkDialog *wndPreferences = NULL;
static GladeXML *gladeFile;
-static gchar *glade_location;
+
static struct browser_window *current_browser;
static int proxy_type;
@@ -45,6 +49,7 @@ static float animation_delay;
static void dialog_response_handler (GtkDialog *dlg, gint res_id);
static gboolean on_dialog_close (GtkDialog *dlg, gboolean stay_alive);
+static void nsgtk_options_theme_combo(void);
/* Declares both widget and callback */
#define DECLARE(x) \
@@ -97,6 +102,12 @@ DECLARE(checkRequestOverwrite);
DECLARE(fileChooserDownloads);
DECLARE(checkFocusNew);
DECLARE(checkNewBlank);
+DECLARE(checkUrlSearch);
+DECLARE(comboSearch);
+DECLARE(combotheme);
+DECLARE(buttonaddtheme);
+DECLARE(sourceButtonTab);
+static GtkWidget *sourceButtonWindow;
DECLARE(spinMarginTop);
DECLARE(spinMarginBottom);
@@ -125,7 +136,9 @@ DECLARE(setDefaultExportOptions);
GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent)
{
- glade_location = g_strconcat(res_dir_location, "options.glade", NULL);
+ char glade_location[strlen(res_dir_location) + SLEN("options.glade")
+ + 1];
+ sprintf(glade_location, "%soptions.glade", res_dir_location);
LOG(("Using '%s' as Glade template file", glade_location));
gladeFile = glade_xml_new(glade_location, NULL, NULL);
@@ -133,7 +146,13 @@ GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent)
wndPreferences = GTK_DIALOG(glade_xml_get_widget(gladeFile,
"dlgPreferences"));
gtk_window_set_transient_for (GTK_WINDOW(wndPreferences), parent);
-
+
+ FIND_WIDGET(sourceButtonTab);
+ FIND_WIDGET(sourceButtonWindow);
+ GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(
+ sourceButtonWindow));
+ gtk_radio_button_set_group(GTK_RADIO_BUTTON(sourceButtonTab), group);
+
/* set the widgets to reflect the current options */
nsgtk_options_load();
@@ -188,6 +207,12 @@ GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent)
CONNECT(checkFocusNew, "toggled");
CONNECT(checkNewBlank, "toggled");
+ CONNECT(checkUrlSearch, "toggled");
+ CONNECT(comboSearch, "changed");
+
+ CONNECT(combotheme, "changed");
+ CONNECT(buttonaddtheme, "clicked");
+ CONNECT(sourceButtonTab, "toggled");
CONNECT(spinMarginTop, "value-changed");
CONNECT(spinMarginBottom, "value-changed");
@@ -247,11 +272,11 @@ GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent)
(value)); \
} while (0)
-#define SET_FILE_CHOOSER(widgt, value) \
+#define SET_FILE_CHOOSER(widget, value) \
do { \
- (widgt) = glade_xml_get_widget(gladeFile, #widgt); \
- gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER((widgt)), \
- (value)); \
+ (widget) = glade_xml_get_widget(gladeFile, #widget); \
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(\
+ (widget)), (value)); \
} while (0)
#define SET_BUTTON(widget) \
@@ -262,22 +287,21 @@ GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent)
void nsgtk_options_load(void)
{
- GtkVBox *combolanguagevbox;
- gchar *languagefile;
+ GtkBox *box;
+ char languagefile[strlen(res_dir_location) + SLEN("languages") + 1];
const char *default_accept_language =
option_accept_language ? option_accept_language : "en";
int combo_row_count = 0;
int active_language = 0;
int proxytype = 0;
FILE *fp;
- char buf[20];
+ char buf[50];
/* Create combobox */
- combolanguagevbox =
- GTK_VBOX(glade_xml_get_widget(gladeFile, "combolanguagevbox"));
+ box = GTK_BOX(glade_xml_get_widget(gladeFile, "combolanguagevbox"));
comboLanguage = gtk_combo_box_new_text();
- languagefile = g_strconcat(res_dir_location, "languages", NULL);
+ sprintf(languagefile, "%slanguages", res_dir_location);
/* Populate combobox from languages file */
fp = fopen((const char *) languagefile, "r");
@@ -309,10 +333,11 @@ void nsgtk_options_load(void)
/** \todo localisation */
gtk_widget_set_tooltip_text(GTK_WIDGET(comboLanguage),
"set preferred language for web pages");
- gtk_box_pack_start(GTK_BOX(combolanguagevbox),
- comboLanguage, FALSE, FALSE, 0);
+ gtk_box_pack_start(box, comboLanguage, FALSE, FALSE, 0);
gtk_widget_show(comboLanguage);
-
+
+ nsgtk_options_theme_combo();
+
SET_ENTRY(entryHomePageURL,
option_homepage_url ? option_homepage_url : "");
SET_BUTTON(setCurrentPage);
@@ -380,7 +405,12 @@ void nsgtk_options_load(void)
SET_CHECK(checkFocusNew, option_focus_new);
SET_CHECK(checkNewBlank, option_new_blank);
+ SET_CHECK(checkUrlSearch, option_search_url_bar);
+ SET_COMBO(comboSearch, option_search_provider);
+ SET_BUTTON(buttonaddtheme);
+ SET_CHECK(sourceButtonTab, option_source_tab);
+
SET_SPIN(spinMarginTop, option_margin_top);
SET_SPIN(spinMarginBottom, option_margin_bottom);
SET_SPIN(spinMarginLeft, option_margin_left);
@@ -417,6 +447,48 @@ static gboolean on_dialog_close (GtkDialog *dlg, gboolean stay_alive)
}
return stay_alive;
}
+
+static void nsgtk_options_theme_combo(void) {
+/* populate theme combo from themelist file */
+ GtkBox *box = GTK_BOX(glade_xml_get_widget(gladeFile, "themehbox"));
+ char buf[50];
+ combotheme = gtk_combo_box_new_text();
+ size_t len = SLEN("themelist") + strlen(res_dir_location) + 1;
+ char themefile[len];
+ if ((combotheme == NULL) || (box == NULL)) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ snprintf(themefile, len, "%sthemelist", res_dir_location);
+ FILE *fp = fopen((const char *)themefile, "r");
+ if (fp == NULL) {
+ LOG(("Failed opening themes file"));
+ warn_user("FileError", (const char *) themefile);
+ return;
+ }
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ /* Ignore blank lines */
+ if (buf[0] == '\0')
+ continue;
+
+ /* Remove trailing \n */
+ buf[strlen(buf) - 1] = '\0';
+
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combotheme), buf);
+ }
+ gtk_combo_box_set_active(GTK_COMBO_BOX(combotheme),
+ option_current_theme);
+ gtk_box_pack_start(box, combotheme, FALSE, TRUE, 0);
+ gtk_widget_show(combotheme);
+}
+
+bool nsgtk_options_combo_theme_add(const char *themename)
+{
+ if (wndPreferences == NULL)
+ return false;
+ gtk_combo_box_append_text(GTK_COMBO_BOX(combotheme), themename);
+ return true;
+}
/* Defines the callback functions for all widgets and specifies
@@ -642,42 +714,44 @@ BUTTON_CLICKED(fontPreview)
END_HANDLER
COMBO_CHANGED(comboButtonType, option_button_type)
- struct gui_window *current = window_list;
-
+ nsgtk_scaffolding *current = scaf_list;
+ option_button_type++;
+ /* value of 0 is reserved for 'unset' */
while (current) {
+ nsgtk_scaffolding_reset_offset(current);
switch(option_button_type) {
- case 0:
+ case 1:
gtk_toolbar_set_style(
- GTK_TOOLBAR(current->scaffold->tool_bar),
+ GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)),
GTK_TOOLBAR_ICONS);
gtk_toolbar_set_icon_size(
- GTK_TOOLBAR(current->scaffold->tool_bar),
+ GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)),
GTK_ICON_SIZE_SMALL_TOOLBAR);
break;
- case 1:
+ case 2:
gtk_toolbar_set_style(
- GTK_TOOLBAR(current->scaffold->tool_bar),
+ GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)),
GTK_TOOLBAR_ICONS);
gtk_toolbar_set_icon_size(
- GTK_TOOLBAR(current->scaffold->tool_bar),
+ GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)),
GTK_ICON_SIZE_LARGE_TOOLBAR);
break;
- case 2:
+ case 3:
gtk_toolbar_set_style(
- GTK_TOOLBAR(current->scaffold->tool_bar),
+ GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)),
GTK_TOOLBAR_BOTH);
gtk_toolbar_set_icon_size(
- GTK_TOOLBAR(current->scaffold->tool_bar),
+ GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)),
GTK_ICON_SIZE_LARGE_TOOLBAR);
break;
- case 3:
+ case 4:
gtk_toolbar_set_style(
- GTK_TOOLBAR(current->scaffold->tool_bar),
+ GTK_TOOLBAR(nsgtk_scaffolding_toolbar(current)),
GTK_TOOLBAR_TEXT);
default:
break;
}
- current = current->next;
+ current = nsgtk_scaffolding_iterate(current);
}
END_HANDLER
@@ -703,6 +777,114 @@ END_HANDLER
CHECK_CHANGED(checkNewBlank, option_new_blank)
END_HANDLER
+CHECK_CHANGED(checkUrlSearch, option_search_url_bar)
+END_HANDLER
+
+COMBO_CHANGED(comboSearch, option_search_provider)
+ nsgtk_scaffolding *current = scaf_list;
+ char *name;
+ /* refresh web search prefs from file */
+ search_web_provider_details(option_search_provider);
+ /* retrieve ico */
+ search_web_retrieve_ico(false);
+ /* callback may handle changing gui */
+ if (search_web_ico() != NULL)
+ gui_window_set_search_ico(search_web_ico());
+ /* set entry */
+ name = search_web_provider_name();
+ if (name == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ continue;
+ }
+ char content[strlen(name) + SLEN("Search ") + 1];
+ sprintf(content, "Search %s", name);
+ free(name);
+ while (current) {
+ nsgtk_scaffolding_set_websearch(current, content);
+ current = nsgtk_scaffolding_iterate(current);
+ }
+END_HANDLER
+
+COMBO_CHANGED(combotheme, option_current_theme)
+ nsgtk_scaffolding *current = scaf_list;
+ char *name;
+ if (option_current_theme != 0) {
+ if (nsgtk_theme_name() != NULL)
+ free(nsgtk_theme_name());
+ name = strdup(gtk_combo_box_get_active_text(
+ GTK_COMBO_BOX(combotheme)));
+ if (name == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ continue;
+ }
+ nsgtk_theme_set_name(name);
+ nsgtk_theme_prepare();
+ } else if (nsgtk_theme_name() != NULL) {
+ free(nsgtk_theme_name());
+ nsgtk_theme_set_name(NULL);
+ }
+ while (current) {
+ nsgtk_theme_implement(current);
+ current = nsgtk_scaffolding_iterate(current);
+ }
+END_HANDLER
+
+BUTTON_CLICKED(buttonaddtheme)
+ char *filename, *directory;
+ size_t len;
+ GtkWidget *fc = gtk_file_chooser_dialog_new(
+ messages_get("gtkAddThemeTitle"),
+ GTK_WINDOW(wndPreferences),
+ GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+ len = SLEN("themes") + strlen(res_dir_location) + 1;
+ char themesfolder[len];
+ snprintf(themesfolder, len, "%sthemes", res_dir_location);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc),
+ themesfolder);
+ gint res = gtk_dialog_run(GTK_DIALOG(fc));
+ if (res == GTK_RESPONSE_ACCEPT) {
+ filename = gtk_file_chooser_get_current_folder(
+ GTK_FILE_CHOOSER(fc));
+ if (strcmp(filename, themesfolder) != 0) {
+ directory = strrchr(filename, '/');
+ *directory = '\0';
+ if (strcmp(filename, themesfolder) != 0) {
+ warn_user(messages_get(
+ "gtkThemeFolderInstructions"),
+ 0);
+ gtk_widget_destroy(GTK_WIDGET(fc));
+ free(filename);
+ free(themesfolder);
+ return FALSE;
+ } else {
+ directory++;
+ }
+ } else {
+ free(filename);
+ filename = gtk_file_chooser_get_filename(
+ GTK_FILE_CHOOSER(fc));
+ if (strcmp(filename, themesfolder) == 0) {
+ warn_user(messages_get("gtkThemeFolderSub"),
+ 0);
+ gtk_widget_destroy(GTK_WIDGET(fc));
+ free(filename);
+ free(themesfolder);
+ return FALSE;
+ }
+ directory = strrchr(filename, '/') + 1;
+ }
+ gtk_widget_destroy(GTK_WIDGET(fc));
+ nsgtk_theme_add(directory);
+ free(filename);
+ }
+
+END_HANDLER
+
+CHECK_CHANGED(sourceButtonTab, option_source_tab)
+END_HANDLER
+
SPIN_CHANGED(spinMarginTop, option_margin_top)
END_HANDLER
diff --git a/gtk/dialogs/gtk_options.h b/gtk/dialogs/gtk_options.h
index cc269d178..9f6602593 100644
--- a/gtk/dialogs/gtk_options.h
+++ b/gtk/dialogs/gtk_options.h
@@ -1,5 +1,6 @@
/*
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -23,8 +24,11 @@
extern GtkDialog *wndPreferences;
-GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent); /** Init options and load window */
+GtkDialog* nsgtk_options_init(struct browser_window *bw, GtkWindow *parent);
+ /** Init options and load window */
void nsgtk_options_load(void); /** Load current options into window */
void nsgtk_options_save(void); /** Save options from window */
+bool nsgtk_options_combo_theme_add(const char *themename);
+ /** add new theme name to combo */
#endif
diff --git a/gtk/dialogs/gtk_source.c b/gtk/dialogs/gtk_source.c
index d52fbb25c..361bcabd9 100644
--- a/gtk/dialogs/gtk_source.c
+++ b/gtk/dialogs/gtk_source.c
@@ -28,8 +28,10 @@
#include "gtk/gtk_gui.h"
#include "gtk/gtk_print.h"
#include "gtk/gtk_selection.h"
+#include "gtk/options.h"
#include "desktop/netsurf.h"
#include "desktop/print.h"
+#include "desktop/options.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/utils.h"
@@ -57,10 +59,10 @@ struct menu_events {
};
static GladeXML *glade_File;
-static gchar *glade_Location;
static struct nsgtk_source_window *nsgtk_source_list = 0;
static char source_zoomlevel = 10;
+void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw);
static void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g);
static gboolean nsgtk_source_delete_event(GtkWindow *window, gpointer g);
static gboolean nsgtk_source_destroy_event(GtkWindow *window, gpointer g);
@@ -102,112 +104,153 @@ MENUEVENT(source_about),
};
void nsgtk_source_dialog_init(GtkWindow *parent, struct browser_window *bw)
-{
- if (bw->current_content->type == CONTENT_HTML) {
- glade_Location = g_strconcat(res_dir_location, "source.glade",
- NULL);
- glade_File = glade_xml_new(glade_Location, NULL, NULL);
- if (glade_File == NULL) {
- LOG(("error loading glade tree"));
- }
-
- char *data = NULL;
+{
+ char glade_Location[strlen(res_dir_location) + SLEN("source.glade")
+ + 1];
+ if (bw->current_content->type != CONTENT_HTML)
+ return;
+
+ if (option_source_tab) {
+ nsgtk_source_tab_init(parent, bw);
+ return;
+ }
+
+ sprintf(glade_Location, "%ssource.glade", res_dir_location);
+ glade_File = glade_xml_new(glade_Location, NULL, NULL);
+ if (glade_File == NULL) {
+ LOG(("error loading glade tree"));
+ }
- utf8_convert_ret r = utf8_from_enc(
- bw->current_content->source_data,
- bw->current_content->data.html.encoding,
- bw->current_content->source_size,
- &data);
- if (r == UTF8_CONVERT_NOMEM) {
- warn_user("NoMemory",0);
- return;
- } else if (r == UTF8_CONVERT_BADENC) {
- warn_user("EncNotRec",0);
- return;
- }
+ char *data = NULL;
+
+ utf8_convert_ret r = utf8_from_enc(
+ bw->current_content->source_data,
+ bw->current_content->data.html.encoding,
+ bw->current_content->source_size,
+ &data);
+ if (r == UTF8_CONVERT_NOMEM) {
+ warn_user("NoMemory",0);
+ return;
+ } else if (r == UTF8_CONVERT_BADENC) {
+ warn_user("EncNotRec",0);
+ return;
+ }
- GtkWindow *wndSource = GTK_WINDOW(glade_xml_get_widget(
- glade_File, "wndSource"));
- GtkWidget *cutbutton = glade_xml_get_widget(
- glade_File, "source_cut");
- GtkWidget *pastebutton = glade_xml_get_widget(
- glade_File, "source_paste");
- GtkWidget *deletebutton = glade_xml_get_widget(
- glade_File, "source_delete");
- GtkWidget *printbutton = glade_xml_get_widget(
- glade_File, "source_print");
- gtk_widget_set_sensitive(cutbutton, FALSE);
- gtk_widget_set_sensitive(pastebutton, FALSE);
- gtk_widget_set_sensitive(deletebutton, FALSE);
- /* for now */
- gtk_widget_set_sensitive(printbutton, FALSE);
-
- struct nsgtk_source_window *thiswindow =
- malloc(sizeof(struct nsgtk_source_window));
- if (thiswindow == NULL) {
- free(data);
- warn_user("NoMemory", 0);
- return;
- }
+ GtkWindow *wndSource = GTK_WINDOW(glade_xml_get_widget(
+ glade_File, "wndSource"));
+ GtkWidget *cutbutton = glade_xml_get_widget(
+ glade_File, "source_cut");
+ GtkWidget *pastebutton = glade_xml_get_widget(
+ glade_File, "source_paste");
+ GtkWidget *deletebutton = glade_xml_get_widget(
+ glade_File, "source_delete");
+ GtkWidget *printbutton = glade_xml_get_widget(
+ glade_File, "source_print");
+ gtk_widget_set_sensitive(cutbutton, FALSE);
+ gtk_widget_set_sensitive(pastebutton, FALSE);
+ gtk_widget_set_sensitive(deletebutton, FALSE);
+ /* for now */
+ gtk_widget_set_sensitive(printbutton, FALSE);
+
+ struct nsgtk_source_window *thiswindow =
+ malloc(sizeof(struct nsgtk_source_window));
+ if (thiswindow == NULL) {
+ free(data);
+ warn_user("NoMemory", 0);
+ return;
+ }
- thiswindow->url = strdup(bw->current_content->url);
- if (thiswindow->url == NULL) {
- free(thiswindow);
- free(data);
- warn_user("NoMemory", 0);
- return;
- }
+ thiswindow->url = strdup(bw->current_content->url);
+ if (thiswindow->url == NULL) {
+ free(thiswindow);
+ free(data);
+ warn_user("NoMemory", 0);
+ return;
+ }
- thiswindow->data = data;
-
- thiswindow->sourcewindow = wndSource;
- thiswindow->bw = bw;
+ thiswindow->data = data;
- char *title = malloc(strlen(bw->current_content->url)
- + SLEN("Source of ") + 1);
- if (title == NULL) {
- free(thiswindow->url);
- free(thiswindow);
- free(data);
- warn_user("NoMemory", 0);
- return;
- }
- sprintf(title, "Source of %s", bw->current_content->url);
-
- thiswindow->next = nsgtk_source_list;
- thiswindow->prev = NULL;
- if (nsgtk_source_list != NULL)
- nsgtk_source_list->prev = thiswindow;
- nsgtk_source_list = thiswindow;
-
- nsgtk_attach_source_menu_handlers(glade_File, thiswindow);
+ thiswindow->sourcewindow = wndSource;
+ thiswindow->bw = bw;
+
+ char title[strlen(bw->current_content->url) + SLEN("Source of ") + 1];
+ sprintf(title, "Source of %s", bw->current_content->url);
+
+ thiswindow->next = nsgtk_source_list;
+ thiswindow->prev = NULL;
+ if (nsgtk_source_list != NULL)
+ nsgtk_source_list->prev = thiswindow;
+ nsgtk_source_list = thiswindow;
- gtk_window_set_title(wndSource, title);
+ nsgtk_attach_source_menu_handlers(glade_File, thiswindow);
- g_signal_connect(G_OBJECT(wndSource), "destroy",
- G_CALLBACK(nsgtk_source_destroy_event),
- thiswindow);
- g_signal_connect(G_OBJECT(wndSource), "delete-event",
- G_CALLBACK(nsgtk_source_delete_event),
- thiswindow);
+ gtk_window_set_title(wndSource, title);
+
+ g_signal_connect(G_OBJECT(wndSource), "destroy",
+ G_CALLBACK(nsgtk_source_destroy_event),
+ thiswindow);
+ g_signal_connect(G_OBJECT(wndSource), "delete-event",
+ G_CALLBACK(nsgtk_source_delete_event),
+ thiswindow);
+
+ GtkTextView *sourceview = GTK_TEXT_VIEW(
+ glade_xml_get_widget(glade_File,
+ "source_view"));
+ PangoFontDescription *fontdesc =
+ pango_font_description_from_string("Monospace 8");
+
+ thiswindow->gv = sourceview;
+ gtk_widget_modify_font(GTK_WIDGET(sourceview), fontdesc);
+ GtkTextBuffer *tb = gtk_text_view_get_buffer(sourceview);
+ gtk_text_buffer_set_text(tb, thiswindow->data, -1);
- GtkTextView *sourceview = GTK_TEXT_VIEW(
- glade_xml_get_widget(glade_File,
- "source_view"));
- PangoFontDescription *fontdesc =
- pango_font_description_from_string("Monospace 8");
-
- thiswindow->gv = sourceview;
- gtk_widget_modify_font(GTK_WIDGET(sourceview), fontdesc);
- GtkTextBuffer *tb = gtk_text_view_get_buffer(sourceview);
- gtk_text_buffer_set_text(tb, thiswindow->data, -1);
-
- gtk_widget_show(GTK_WIDGET(wndSource));
+ gtk_widget_show(GTK_WIDGET(wndSource));
- free(title);
+}
+void nsgtk_source_tab_init(GtkWindow *parent, struct browser_window *bw)
+{
+ char *ndata = 0;
+ utf8_convert_ret r = utf8_from_enc(
+ bw->current_content->source_data,
+ bw->current_content->data.html.encoding,
+ bw->current_content->source_size,
+ &ndata);
+ if (r == UTF8_CONVERT_NOMEM) {
+ warn_user("NoMemory",0);
+ return;
+ } else if (r == UTF8_CONVERT_BADENC) {
+ warn_user("EncNotRec",0);
+ return;
+ }
+ gchar *filename;
+ char *fileurl;
+ gint handle = g_file_open_tmp("nsgtksourceXXXXXX", &filename, NULL);
+ close (handle); /* in case it was binary mode */
+ FILE *f = fopen(filename, "w");
+ fprintf(f, "%s", ndata);
+ fclose(f);
+ free(ndata);
+ fileurl = path_to_url(filename);
+ g_free(filename);
+ if (fileurl == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ struct browser_window *newbw = browser_window_create(fileurl, bw,
+ NULL, false, true);
+ free(fileurl);
+ if (newbw->current_content) {
+ newbw->current_content->title = malloc(
+ strlen(bw->current_content->url) +
+ SLEN("source of ") + 1);
+ if (newbw->current_content->title == NULL)
+ return;
+ sprintf(newbw->current_content->title, "source of %s",
+ bw->current_content->url);
}
}
+
void nsgtk_attach_source_menu_handlers(GladeXML *xml, gpointer g)
{
struct menu_events *event = source_menu_events;
@@ -264,7 +307,7 @@ void nsgtk_source_file_save(GtkWindow *parent, const char *filename,
{
FILE *f;
bool auth = true;
- char temp[15];
+ char temp[255];
GtkWidget *notif, *label;
if (!(access(filename, F_OK))) {
@@ -277,21 +320,18 @@ void nsgtk_source_file_save(GtkWindow *parent, const char *filename,
GTK_STOCK_CANCEL,
GTK_RESPONSE_REJECT,
NULL);
- char *warn;
const char *format = messages_get("gtkOverwrite");
- int len = strlen(filename) + strlen(format);
-
+ int len = strlen(filename) + strlen(format) + SLEN("\n\n") + 1;
+ char warn[len];
auth = false;
- warn = malloc(len);
- if (warn == NULL) {
- warn_user("NoMemory", 0);
- return;
- }
-
- snprintf(warn, len, format, filename);
+ warn[0] = '\n';
+ snprintf(warn + 1, len - 2, format, filename);
+ len = strlen(warn);
+ warn[len - 1] = '\n';
+ warn[len] = '\0';
- label = gtk_label_new(g_strconcat("\n",warn,"\n", NULL));
+ label = gtk_label_new(warn);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(confd)->vbox),
label);
gtk_widget_show(label);
@@ -299,16 +339,19 @@ void nsgtk_source_file_save(GtkWindow *parent, const char *filename,
auth = true;
}
gtk_widget_destroy(confd);
- free(warn);
}
if (auth) {
f = fopen(filename, "w+");
fprintf(f, "%s", data);
fclose(f);
- strcpy(temp, messages_get("gtkSaveConfirm"));
+ snprintf(temp, sizeof(temp), "\n %s"
+ " \n",
+ messages_get("gtkSaveConfirm"));
} else {
- strcpy(temp, messages_get("gtkSaveCancelled"));
+ snprintf(temp, sizeof(temp), "\n %s"
+ " \n",
+ messages_get("gtkSaveCancelled"));
}
notif = gtk_dialog_new_with_buttons(temp,
@@ -316,8 +359,7 @@ void nsgtk_source_file_save(GtkWindow *parent, const char *filename,
GTK_RESPONSE_NONE, NULL);
g_signal_connect_swapped(notif, "response",
G_CALLBACK(gtk_widget_destroy), notif);
- label = gtk_label_new(g_strconcat("\n ", temp,
- " \n", NULL));
+ label = gtk_label_new(temp);
gtk_container_add(GTK_CONTAINER(GTK_DIALOG(notif)->vbox), label);
gtk_widget_show_all(notif);
}
diff --git a/gtk/gtk_download.c b/gtk/gtk_download.c
index 23b30ef88..fb8541587 100644
--- a/gtk/gtk_download.c
+++ b/gtk/gtk_download.c
@@ -33,6 +33,7 @@
#include "gtk/gtk_scaffolding.h"
#include "gtk/options.h"
#include "gtk/gtk_download.h"
+#include "gtk/gtk_window.h"
#define UPDATE_RATE 500 /* In milliseconds */
#define GLADE_NAME "downloads.glade"
@@ -86,9 +87,9 @@ static gboolean nsgtk_download_handle_error (GError *error);
void nsgtk_download_init()
{
- gchar *glade_location = g_strconcat(res_dir_location, GLADE_NAME, NULL);
+ char glade_location[strlen(res_dir_location) + SLEN(GLADE_NAME) + 1];
+ sprintf(glade_location, "%s" GLADE_NAME, res_dir_location);
GladeXML *gladeFile = glade_xml_new(glade_location, NULL, NULL);
- g_free(glade_location);
nsgtk_download_buttons =
glade_xml_get_widget_prefix(gladeFile, "button");
@@ -202,11 +203,12 @@ struct gui_download_window *gui_download_window_create(const char *url,
gchar *filename;
gchar *destination;
gboolean unknown_size = total_size == 0;
- const gchar *size = (total_size == 0 ?
+ const char *size = (total_size == 0 ?
messages_get("gtkUnknownSize") :
human_friendly_bytesize(total_size));
- nsgtk_download_parent = nsgtk_scaffolding_get_window(gui);
+ nsgtk_download_parent = nsgtk_scaffolding_window(nsgtk_get_scaffold(
+ gui));
struct gui_download_window *download = malloc(sizeof *download);
if (url_nice(url, &filename, false) != URL_FUNC_OK)
@@ -488,8 +490,9 @@ gboolean nsgtk_download_update(gboolean force_update)
void nsgtk_download_store_update_item (struct gui_download_window *dl)
{
gchar *info = nsgtk_download_info_to_string(dl);
- gchar *speed = g_strconcat(human_friendly_bytesize(dl->speed), "/s",
- NULL);
+ char *human = human_friendly_bytesize(dl->speed);
+ char speed[strlen(human) + SLEN("/s") + 1];
+ sprintf(speed, "%s/s", human);
gchar *time = nsgtk_download_time_to_string(dl->time_remaining);
gboolean pulse = dl->status == NSGTK_DOWNLOAD_WORKING;
@@ -508,7 +511,6 @@ void nsgtk_download_store_update_item (struct gui_download_window *dl)
-1);
g_free(info);
- g_free(speed);
g_free(time);
}
@@ -634,7 +636,7 @@ gchar* nsgtk_download_dialog_show (gchar *filename, gchar *domain,
{
enum { GTK_RESPONSE_DOWNLOAD, GTK_RESPONSE_SAVE_AS };
GtkWidget *dialog;
- gchar *destination = NULL;
+ char *destination = NULL;
gchar *message = g_strdup(messages_get("gtkStartDownload"));
gchar *info = g_strdup_printf(messages_get("gtkInfo"), filename,
domain, size);
@@ -682,9 +684,15 @@ gchar* nsgtk_download_dialog_show (gchar *filename, gchar *domain,
break;
}
case GTK_RESPONSE_DOWNLOAD: {
- destination = g_strconcat(option_downloads_directory,
- "/", filename, NULL);
- /* Test if file already exists and display overwrite
+ destination = malloc(strlen(option_downloads_directory)
+ + strlen(filename) + SLEN("/") + 1);
+ if (destination == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ break;
+ }
+ sprintf(destination, "%s/%s",
+ option_downloads_directory, filename);
+ /* Test if file already exists and display overwrite
* confirmation if needed */
if (g_file_test(destination, G_FILE_TEST_EXISTS)
&& option_request_overwrite) {
@@ -711,7 +719,7 @@ gchar* nsgtk_download_dialog_show (gchar *filename, gchar *domain,
gtk_button_set_image(GTK_BUTTON(button),
gtk_image_new_from_stock(
"gtk-save",
- GTK_ICON_SIZE_BUTTON));
+ GTK_ICON_SIZE_BUTTON));
gint result = gtk_dialog_run(GTK_DIALOG(
dialog));
diff --git a/gtk/gtk_gui.c b/gtk/gtk_gui.c
index 971c3fbf2..43860e9ab 100644
--- a/gtk/gtk_gui.c
+++ b/gtk/gtk_gui.c
@@ -43,6 +43,7 @@
#include "desktop/netsurf.h"
#include "desktop/options.h"
#include "desktop/save_pdf/pdf_plotters.h"
+#include "desktop/searchweb.h"
#include "desktop/textinput.h"
#include "gtk/gtk_gui.h"
#include "gtk/dialogs/gtk_options.h"
@@ -68,15 +69,23 @@ char *default_stylesheet_url;
char *quirks_stylesheet_url;
char *adblock_stylesheet_url;
char *options_file_location;
-char *glade_file_location;
+char *glade_netsurf_file_location;
+char *glade_password_file_location;
+char *glade_warning_file_location;
+char *glade_login_file_location;
+char *glade_ssl_file_location;
+char *glade_toolbar_file_location;
+char *toolbar_indices_file_location;
char *res_dir_location;
char *print_options_file_location;
-struct gui_window *search_current_window = 0;
-
GtkWindow *wndAbout;
GtkWindow *wndWarning;
-GladeXML *gladeWindows;
+GladeXML *gladeNetsurf;
+GladeXML *gladePassword;
+GladeXML *gladeWarning;
+GladeXML *gladeLogin;
+GladeXML *gladeSsl;
GtkWindow *wndTooltip;
GtkLabel *labelTooltip;
@@ -195,12 +204,28 @@ void gui_init(int argc, char** argv)
check_homedir();
find_resource(buf, "netsurf.glade", "./gtk/res/netsurf.glade");
- LOG(("Using '%s' as Glade template file", buf));
- glade_file_location = strdup(buf);
+ LOG(("Using '%s' as Netsurf glade template file", buf));
+ glade_netsurf_file_location = strdup(buf);
buf[strlen(buf)- 13] = 0;
LOG(("Using '%s' as Resources directory", buf));
res_dir_location = strdup(buf);
+
+ find_resource(buf, "password.glade", "./gtk/res/password.glade");
+ LOG(("Using '%s' as password glade template file", buf));
+ glade_password_file_location = strdup(buf);
+
+ find_resource(buf, "warning.glade", "./gtk/res/warning.glade");
+ LOG(("Using '%s' as warning glade template file", buf));
+ glade_warning_file_location = strdup(buf);
+
+ find_resource(buf, "login.glade", "./gtk/res/login.glade");
+ LOG(("Using '%s' as login glade template file", buf));
+ glade_login_file_location = strdup(buf);
+
+ find_resource(buf, "ssl.glade", "./gtk/res/ssl.glade");
+ LOG(("Using '%s' as ssl glade template file", buf));
+ glade_ssl_file_location = strdup(buf);
find_resource(buf, "Aliases", "./gtk/res/Aliases");
LOG(("Using '%s' as Aliases file", buf));
@@ -208,17 +233,42 @@ void gui_init(int argc, char** argv)
die("Unable to initialise HTML parsing library.\n");
glade_init();
- gladeWindows = glade_xml_new(glade_file_location, NULL, NULL);
- if (gladeWindows == NULL)
- die("Unable to load Glade window definitions.\n");
- glade_xml_signal_autoconnect(gladeWindows);
+ gladeWarning = glade_xml_new(glade_warning_file_location, NULL, NULL);
+ if (gladeWarning == NULL)
+ die("Unable to load glade warning window definitions.\n");
+ glade_xml_signal_autoconnect(gladeWarning);
+
+ gladeNetsurf = glade_xml_new(glade_netsurf_file_location, NULL, NULL);
+ if (gladeNetsurf == NULL)
+ die("Unable to load glade Netsurf window definitions.\n");
+ glade_xml_signal_autoconnect(gladeNetsurf);
+
+ gladePassword = glade_xml_new(glade_password_file_location, NULL, NULL);
+ if (gladePassword == NULL)
+ die("Unable to load glade password window definitions.\n");
+ glade_xml_signal_autoconnect(gladePassword);
+
+ gladeLogin = glade_xml_new(glade_login_file_location, NULL, NULL);
+ if (gladeLogin == NULL)
+ die("Unable to load glade login window definitions.\n");
+ glade_xml_signal_autoconnect(gladeLogin);
+
+ gladeSsl = glade_xml_new(glade_ssl_file_location, NULL, NULL);
+ if (gladeSsl == NULL)
+ die("Unable to load glade ssl window definitions.\n");
+ glade_xml_signal_autoconnect(gladeSsl);
+
+ find_resource(buf, "toolbar.glade", "./gtk/res/toolbar.glade");
+ LOG(("Using '%s' as glade toolbar file", buf));
+ glade_toolbar_file_location = strdup(buf);
find_resource(buf, "netsurf.xpm", "./gtk/res/netsurf.xpm");
gtk_window_set_default_icon_from_file(buf, NULL);
- wndTooltip = GTK_WINDOW(glade_xml_get_widget(gladeWindows, "wndTooltip"));
- labelTooltip = GTK_LABEL(glade_xml_get_widget(gladeWindows, "tooltip"));
-
+ /* superfluous ? */
+ wndTooltip = GTK_WINDOW(glade_xml_get_widget(gladeNetsurf, "wndTooltip"));
+ labelTooltip = GTK_LABEL(glade_xml_get_widget(gladeNetsurf, "tooltip"));
+
nsgtk_completion_init();
/* This is an ugly hack to just get the new-style throbber going.
@@ -321,12 +371,25 @@ void gui_init(int argc, char** argv)
LOG(("Using '%s' as Print Settings file", buf));
print_options_file_location = strdup(buf);
+ find_resource(buf, "SearchEngines", "./gtk/res/SearchEngines");
+ LOG(("Using '%s' as Search Engines file", buf));
+ search_engines_file_location = strdup(buf);
+
+ find_resource(buf, "default.ico", "./gtk/res/default.ico");
+ LOG(("Using '%s' as default search ico", buf));
+ search_default_ico_location = strdup(buf);
+
+ find_resource(buf, "toolbarIndices", "./gtk/res/toolbarIndices");
+ LOG(("Using '%s' as custom toolbar settings file", buf));
+ toolbar_indices_file_location = strdup(buf);
+
urldb_load(option_url_file);
urldb_load_cookies(option_cookie_file);
+
+ /* superfluous ? */
+ wndAbout = GTK_WINDOW(glade_xml_get_widget(gladeNetsurf, "wndAbout"));
- wndAbout = GTK_WINDOW(glade_xml_get_widget(gladeWindows, "wndAbout"));
-
- wndWarning = GTK_WINDOW(glade_xml_get_widget(gladeWindows, "wndWarning"));
+ wndWarning = GTK_WINDOW(glade_xml_get_widget(gladeWarning, "wndWarning"));
nsgtk_history_init();
nsgtk_download_init();
@@ -428,6 +491,9 @@ void gui_quit(void)
free(option_cookie_file);
free(option_cookie_jar);
free(print_options_file_location);
+ free(search_engines_file_location);
+ free(search_default_ico_location);
+ free(toolbar_indices_file_location);
gtk_fetch_filetype_fin();
/* We don't care if this fails as we're about to die, anyway */
hubbub_finalise(myrealloc, NULL);
@@ -490,15 +556,6 @@ void gui_launch_url(const char *url)
{
}
-
-bool gui_search_term_highlighted(struct gui_window *g,
- unsigned start_offset, unsigned end_offset,
- unsigned *start_idx, unsigned *end_idx)
-{
- return false;
-}
-
-
void warn_user(const char *warning, const char *detail)
{
char buf[300]; /* 300 is the size the RISC OS GUI uses */
@@ -510,7 +567,7 @@ void warn_user(const char *warning, const char *detail)
detail ? detail : "");
buf[sizeof(buf) - 1] = 0;
- gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(gladeWindows, "labelWarning")), buf);
+ gtk_label_set_text(GTK_LABEL(glade_xml_get_widget(gladeWarning, "labelWarning")), buf);
gtk_widget_show_all(GTK_WIDGET(wndWarning));
}
@@ -536,7 +593,7 @@ static void nsgtk_create_ssl_verify_window(struct browser_window *bw,
struct content *c, const struct ssl_cert_info *certs,
unsigned long num)
{
- GladeXML *x = glade_xml_new(glade_file_location, NULL, NULL);
+ GladeXML *x = glade_xml_new(glade_ssl_file_location, NULL, NULL);
GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndSSLProblem"));
GtkButton *accept, *reject;
void **session = calloc(sizeof(void *), 4);
@@ -618,7 +675,7 @@ utf8_convert_ret utf8_from_local_encoding(const char *string, size_t len,
char *path_to_url(const char *path)
{
- char *r = malloc(strlen(path) + 7 + 1);
+ char *r = malloc(strlen(path) + SLEN("file://") + 1);
strcpy(r, "file://");
strcat(r, path);
@@ -640,7 +697,7 @@ bool cookies_update(const char *domain, const struct cookie_data *data)
void PDF_Password(char **owner_pass, char **user_pass, char *path)
{
- GladeXML *x = glade_xml_new(glade_file_location, NULL, NULL);
+ GladeXML *x = glade_xml_new(glade_password_file_location, NULL, NULL);
GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndPDFPassword"));
GtkButton *ok, *no;
void **data = malloc(5 * sizeof(void *));
diff --git a/gtk/gtk_gui.h b/gtk/gtk_gui.h
index 8c9aa0afb..21bc84202 100644
--- a/gtk/gtk_gui.h
+++ b/gtk/gtk_gui.h
@@ -25,8 +25,18 @@
#include <glade/glade.h>
extern bool gui_in_multitask;
-extern GladeXML *gladeWindows;
-extern char *glade_file_location;
+extern GladeXML *gladeNetsurf;
+extern GladeXML *gladePassword;
+extern GladeXML *gladeWarning;
+extern GladeXML *gladeLogin;
+extern GladeXML *gladeSsl;
+extern char *glade_netsurf_file_location;
+extern char *glade_password_file_location;
+extern char *glade_warning_file_location;
+extern char *glade_login_file_location;
+extern char *glade_ssl_file_location;
+extern char *glade_toolbar_file_location;
+extern char *toolbar_indices_file_location;
extern char *options_file_location;
extern char *res_dir_location;
extern char *print_options_file_location;
diff --git a/gtk/gtk_history.c b/gtk/gtk_history.c
index e0376dad5..9bcb584d6 100644
--- a/gtk/gtk_history.c
+++ b/gtk/gtk_history.c
@@ -107,9 +107,9 @@ void nsgtk_history_init(void)
dateAt = messages_get("DateAt");
domainAll = messages_get("DomainAll");
- gchar *glade_location = g_strconcat(res_dir_location, GLADE_NAME, NULL);
+ char glade_location[strlen(res_dir_location) + SLEN(GLADE_NAME) + 1];
+ sprintf(glade_location, "%s" GLADE_NAME, res_dir_location);
gladeFile = glade_xml_new(glade_location, NULL, NULL);
- g_free(glade_location);
glade_xml_signal_autoconnect(gladeFile);
wndHistory = GTK_WINDOW(glade_xml_get_widget(gladeFile,
@@ -500,23 +500,23 @@ void nsgtk_history_search_clear (GtkEntry *entry)
gchar *nsgtk_history_date_parse(time_t visit_time)
{
- gchar *date_string = malloc(30);
- gchar format[30];
+ char *date_string = malloc(30);
+ char format[30];
time_t current_time = time(NULL);
- gint current_day = localtime(&current_time)->tm_yday;
+ int current_day = localtime(&current_time)->tm_yday;
struct tm *visit_date = localtime(&visit_time);
if (visit_date->tm_yday == current_day)
- g_snprintf(format, 30, "%s %s %%I:%%M %%p",
+ snprintf(format, 30, "%s %s %%I:%%M %%p",
dateToday, dateAt);
else if (current_day - visit_date->tm_yday == 1)
- g_snprintf(format, 30, "%s %s %%I:%%M %%p",
+ snprintf(format, 30, "%s %s %%I:%%M %%p",
dateYesterday, dateAt);
else if (current_day - visit_date->tm_yday < 7)
- g_snprintf(format, 30, "%%A %s %%I:%%M %%p",
+ snprintf(format, 30, "%%A %s %%I:%%M %%p",
dateAt);
else
- g_snprintf(format, 30, "%%B %%d, %%Y");
+ snprintf(format, 30, "%%B %%d, %%Y");
strftime(date_string, 30, format, visit_date);
diff --git a/gtk/gtk_login.c b/gtk/gtk_login.c
index d2535515e..3bb11a66b 100644
--- a/gtk/gtk_login.c
+++ b/gtk/gtk_login.c
@@ -74,7 +74,7 @@ void create_login_window(struct browser_window *bw, const char *host,
* the widgets we're interested in.
*/
- GladeXML *x = glade_xml_new(glade_file_location, NULL, NULL);
+ GladeXML *x = glade_xml_new(glade_login_file_location, NULL, NULL);
GtkWindow *wnd = GTK_WINDOW(glade_xml_get_widget(x, "wndLogin"));
GtkLabel *lhost, *lrealm;
GtkEntry *euser, *epass;
diff --git a/gtk/gtk_menu.c b/gtk/gtk_menu.c
new file mode 100644
index 000000000..e7e02d77b
--- /dev/null
+++ b/gtk/gtk_menu.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include "gtk/gtk_menu.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+
+static struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup *);
+static struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu(
+ GtkAccelGroup *);
+static struct nsgtk_images_submenu *nsgtk_menu_images_submenu(GtkAccelGroup *);
+static struct nsgtk_toolbars_submenu *nsgtk_menu_toolbars_submenu(
+ GtkAccelGroup *);
+static struct nsgtk_debugging_submenu *nsgtk_menu_debugging_submenu(
+ GtkAccelGroup *);
+static bool nsgtk_menu_add_image_item(GtkMenu *menu,
+ GtkImageMenuItem **item, const char *message,
+ const char *messageAccel, GtkAccelGroup *group);
+
+/**
+ * adds image menu item to specified menu
+ * \param menu the menu to add the item to
+ * \param item a pointer to the item's location in the menu struct
+ * \param message the menu item I18n lookup value
+ * \param messageAccel the menu item accelerator I18n lookup value
+ * \param group the 'global' in a gtk sense accelerator group
+ */
+
+bool nsgtk_menu_add_image_item(GtkMenu *menu,
+ GtkImageMenuItem **item, const char *message,
+ const char *messageAccel, GtkAccelGroup *group)
+{
+ unsigned int key;
+ GdkModifierType mod;
+ *item = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_with_mnemonic(
+ messages_get(message)));
+ if (*item == NULL)
+ return false;
+ gtk_accelerator_parse(messages_get(messageAccel), &key, &mod);
+ if (key > 0)
+ gtk_widget_add_accelerator(GTK_WIDGET(*item), "activate",
+ group, key, mod, GTK_ACCEL_VISIBLE);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(*item));
+ gtk_widget_show(GTK_WIDGET(*item));
+ return true;
+}
+
+#define IMAGE_ITEM(p, q, r, s, t)\
+ nsgtk_menu_add_image_item(s->p##_menu, &(s->q##_menuitem), #r,\
+ #r "Accel", t);
+
+#define CHECK_ITEM(p, q, r, s)\
+ s->q##_menuitem = GTK_CHECK_MENU_ITEM(\
+ gtk_check_menu_item_new_with_mnemonic(\
+ messages_get(#r)));\
+ if ((s->q##_menuitem != NULL) && (s->p##_menu != NULL)) {\
+ gtk_menu_shell_append(GTK_MENU_SHELL(s->p##_menu),\
+ GTK_WIDGET(s->q##_menuitem));\
+ gtk_widget_show(GTK_WIDGET(s->q##_menuitem));\
+ }
+
+#define SET_SUBMENU(q, r)\
+ r->q##_submenu = nsgtk_menu_##q##_submenu(group);\
+ if ((r->q##_submenu != NULL) && (r->q##_submenu->q##_menu != NULL) && \
+ (r->q##_menuitem != NULL)) {\
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(r->q##_menuitem),\
+ GTK_WIDGET(r->q##_submenu->q##_menu));\
+ }
+
+#define ADD_SEP(q, r)\
+ w = gtk_separator_menu_item_new();\
+ if ((w != NULL) && (r->q##_menu != NULL)) {\
+ gtk_menu_shell_append(GTK_MENU_SHELL(r->q##_menu), w);\
+ gtk_widget_show(w);\
+ }
+
+/**
+ * creates the a file menu
+ * \param group the 'global' in a gtk sense accelerator reference
+ */
+struct nsgtk_file_menu *nsgtk_menu_file_menu(GtkAccelGroup *group)
+{
+ GtkWidget *w;
+ struct nsgtk_file_menu *ret = malloc(sizeof(struct nsgtk_file_menu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->file_menu = GTK_MENU(gtk_menu_new());
+ if (ret->file_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(file, newwindow, gtkNewWindow, ret, group)
+ IMAGE_ITEM(file, newtab, gtkNewTab, ret, group)
+ IMAGE_ITEM(file, openfile, gtkOpenFile, ret, group)
+ IMAGE_ITEM(file, closewindow, gtkCloseWindow, ret, group)
+ ADD_SEP(file, ret)
+ IMAGE_ITEM(file, savepage, gtkSavePage, ret, group)
+ IMAGE_ITEM(file, export, gtkExport, ret, group)
+ ADD_SEP(file, ret)
+ IMAGE_ITEM(file, printpreview, gtkPrintPreview, ret, group)
+ IMAGE_ITEM(file, print, gtkPrint, ret, group)
+ ADD_SEP(file, ret)
+ IMAGE_ITEM(file, quit, gtkQuitMenu, ret, group)
+ SET_SUBMENU(export, ret)
+ return ret;
+}
+
+/**
+* creates an edit menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_edit_menu *nsgtk_menu_edit_menu(GtkAccelGroup *group)
+{
+ GtkWidget *w;
+ struct nsgtk_edit_menu *ret = malloc(sizeof(struct nsgtk_edit_menu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->edit_menu = GTK_MENU(gtk_menu_new());
+ if (ret->edit_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(edit, cut, gtkCut, ret, group)
+ IMAGE_ITEM(edit, copy, gtkCopy, ret, group)
+ IMAGE_ITEM(edit, paste, gtkPaste, ret, group)
+ IMAGE_ITEM(edit, delete, gtkDelete, ret, group)
+ ADD_SEP(edit, ret)
+ IMAGE_ITEM(edit, selectall, gtkSelectAll, ret, group)
+ ADD_SEP(edit, ret)
+ IMAGE_ITEM(edit, find, gtkFind, ret, group)
+ ADD_SEP(edit, ret)
+ IMAGE_ITEM(edit, preferences, gtkPreferences, ret, group)
+ return ret;
+}
+
+/**
+* creates a view menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_view_menu *nsgtk_menu_view_menu(GtkAccelGroup *group)
+{
+ GtkWidget *w;
+ struct nsgtk_view_menu *ret = malloc(sizeof(struct nsgtk_view_menu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->view_menu = GTK_MENU(gtk_menu_new());
+ if (ret->view_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(view, stop, gtkStop, ret, group)
+ IMAGE_ITEM(view, reload, gtkReload, ret, group)
+ ADD_SEP(view, ret)
+ IMAGE_ITEM(view, scaleview, gtkScaleView, ret, group)
+ IMAGE_ITEM(view, fullscreen, gtkFullScreen, ret, group)
+ IMAGE_ITEM(view, viewsource, gtkViewSource, ret, group)
+ ADD_SEP(view, ret)
+ IMAGE_ITEM(view, images, gtkImages, ret, group)
+ IMAGE_ITEM(view, toolbars, gtkToolbars, ret, group)
+ ADD_SEP(view, ret)
+ IMAGE_ITEM(view, downloads, gtkDownloads, ret, group)
+ IMAGE_ITEM(view, savewindowsize, gtkSaveWindowSize, ret, group)
+ IMAGE_ITEM(view, debugging, gtkDebugging, ret, group)
+ SET_SUBMENU(scaleview, ret)
+ SET_SUBMENU(images, ret)
+ SET_SUBMENU(toolbars, ret)
+ SET_SUBMENU(debugging, ret)
+ return ret;
+}
+
+/**
+* creates a nav menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_nav_menu *nsgtk_menu_nav_menu(GtkAccelGroup *group)
+{
+ GtkWidget *w;
+ struct nsgtk_nav_menu *ret = malloc(sizeof(struct nsgtk_nav_menu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->nav_menu = GTK_MENU(gtk_menu_new());
+ if (ret->nav_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(nav, back, gtkBack, ret, group)
+ IMAGE_ITEM(nav, forward, gtkForward, ret, group)
+ IMAGE_ITEM(nav, home, gtkHome, ret, group)
+ ADD_SEP(nav, ret)
+ IMAGE_ITEM(nav, localhistory, gtkLocalHistory, ret, group)
+ IMAGE_ITEM(nav, globalhistory, gtkGlobalHistory, ret, group)
+ ADD_SEP(nav, ret)
+ IMAGE_ITEM(nav, addbookmarks, gtkAddBookMarks, ret, group)
+ IMAGE_ITEM(nav, showbookmarks, gtkShowBookMarks, ret, group)
+ ADD_SEP(nav, ret)
+ IMAGE_ITEM(nav, openlocation, gtkOpenLocation, ret, group)
+ return ret;
+}
+
+/**
+* creates a tabs menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_tabs_menu *nsgtk_menu_tabs_menu(GtkAccelGroup *group)
+{
+ struct nsgtk_tabs_menu *ret = malloc(sizeof(struct nsgtk_tabs_menu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->tabs_menu = GTK_MENU(gtk_menu_new());
+ if (ret->tabs_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(tabs, nexttab, gtkNextTab, ret, group)
+ IMAGE_ITEM(tabs, prevtab, gtkPrevTab, ret, group)
+ IMAGE_ITEM(tabs, closetab, gtkCloseTab, ret, group)
+ return ret;
+}
+
+/**
+* creates a help menu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_help_menu *nsgtk_menu_help_menu(GtkAccelGroup *group)
+{
+ GtkWidget *w;
+ struct nsgtk_help_menu *ret = malloc(sizeof(struct nsgtk_help_menu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->help_menu = GTK_MENU(gtk_menu_new());
+ if (ret->help_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(help, contents, gtkContents, ret, group)
+ IMAGE_ITEM(help, guide, gtkGuide, ret, group)
+ IMAGE_ITEM(help, info, gtkUserInformation, ret, group)
+ ADD_SEP(help, ret)
+ IMAGE_ITEM(help, about, gtkAbout, ret, group)
+ return ret;
+}
+
+/**
+* creates an export submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_export_submenu *nsgtk_menu_export_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_export_submenu *ret = malloc(sizeof(struct
+ nsgtk_export_submenu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->export_menu = GTK_MENU(gtk_menu_new());
+ if (ret->export_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(export, plaintext, gtkPlainText, ret, group)
+ IMAGE_ITEM(export, drawfile, gtkDrawFile, ret, group)
+ IMAGE_ITEM(export, postscript, gtkPostScript, ret, group)
+ IMAGE_ITEM(export, pdf, gtkPDF, ret, group)
+ return ret;
+}
+
+/**
+* creates a scaleview submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_scaleview_submenu *nsgtk_menu_scaleview_submenu(
+ GtkAccelGroup *group)
+{
+ struct nsgtk_scaleview_submenu *ret =
+ malloc(sizeof(struct nsgtk_scaleview_submenu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->scaleview_menu = GTK_MENU(gtk_menu_new());
+ if (ret->scaleview_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(scaleview, zoomplus, gtkZoomPlus, ret, group)
+ IMAGE_ITEM(scaleview, zoomnormal, gtkZoomNormal, ret, group)
+ IMAGE_ITEM(scaleview, zoomminus, gtkZoomMinus, ret, group)
+ return ret;
+}
+
+/**
+* creates an images submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_images_submenu *nsgtk_menu_images_submenu(GtkAccelGroup *group)
+{
+ struct nsgtk_images_submenu *ret =
+ malloc(sizeof(struct nsgtk_images_submenu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->images_menu = GTK_MENU(gtk_menu_new());
+ if (ret->images_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ CHECK_ITEM(images, foregroundimages, gtkForegroundImages, ret)
+ CHECK_ITEM(images, backgroundimages, gtkBackgroundImages, ret)
+ return ret;
+}
+
+/**
+* creates a toolbars submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_toolbars_submenu *nsgtk_menu_toolbars_submenu(
+ GtkAccelGroup *group)
+{
+ struct nsgtk_toolbars_submenu *ret =
+ malloc(sizeof(struct nsgtk_toolbars_submenu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->toolbars_menu = GTK_MENU(gtk_menu_new());
+ if (ret->toolbars_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ CHECK_ITEM(toolbars, menubar, gtkMenuBar, ret)
+ if (ret->menubar_menuitem != NULL)
+ gtk_check_menu_item_set_active(ret->menubar_menuitem, TRUE);
+ CHECK_ITEM(toolbars, toolbar, gtkToolBar, ret)
+ if (ret->toolbar_menuitem != NULL)
+ gtk_check_menu_item_set_active(ret->toolbar_menuitem, TRUE);
+ CHECK_ITEM(toolbars, statusbar, gtkStatusBar, ret)
+ if (ret->statusbar_menuitem != NULL)
+ gtk_check_menu_item_set_active(ret->statusbar_menuitem, TRUE);
+ return ret;
+}
+
+/**
+* creates a debugging submenu
+* \param group the 'global' in a gtk sense accelerator reference
+*/
+
+struct nsgtk_debugging_submenu *nsgtk_menu_debugging_submenu(
+ GtkAccelGroup *group)
+{
+ struct nsgtk_debugging_submenu *ret =
+ malloc(sizeof(struct nsgtk_debugging_submenu));
+ if (ret == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ ret->debugging_menu = GTK_MENU(gtk_menu_new());
+ if (ret->debugging_menu == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(ret);
+ return NULL;
+ }
+ IMAGE_ITEM(debugging, toggledebugging, gtkToggleDebugging, ret, group)
+ IMAGE_ITEM(debugging, saveboxtree, gtkSaveBoxTree, ret, group)
+ IMAGE_ITEM(debugging, savedomtree, gtkSaveDomTree, ret, group)
+ return ret;
+}
+
+#undef CHECK_ITEM
+#undef IMAGE_ITEM
+#undef SET_SUBMENU
+#undef ADD_SEP
+
diff --git a/gtk/gtk_menu.h b/gtk/gtk_menu.h
new file mode 100644
index 000000000..77199604b
--- /dev/null
+++ b/gtk/gtk_menu.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef _NETSURF_GTK_MENU_H_
+#define _NETSURF_GTK_MENU_H_
+
+#include <gtk/gtk.h>
+
+struct nsgtk_file_menu {
+ GtkMenu *file_menu;
+ GtkImageMenuItem *newwindow_menuitem;
+ GtkImageMenuItem *newtab_menuitem;
+ GtkImageMenuItem *openfile_menuitem;
+ GtkImageMenuItem *closewindow_menuitem;
+ GtkImageMenuItem *savepage_menuitem;
+ GtkImageMenuItem *export_menuitem;
+ struct nsgtk_export_submenu *export_submenu;
+ GtkImageMenuItem *printpreview_menuitem;
+ GtkImageMenuItem *print_menuitem;
+ GtkImageMenuItem *quit_menuitem;
+};
+
+struct nsgtk_edit_menu {
+ GtkMenu *edit_menu;
+ GtkImageMenuItem *cut_menuitem;
+ GtkImageMenuItem *copy_menuitem;
+ GtkImageMenuItem *paste_menuitem;
+ GtkImageMenuItem *delete_menuitem;
+ GtkImageMenuItem *selectall_menuitem;
+ GtkImageMenuItem *find_menuitem;
+ GtkImageMenuItem *preferences_menuitem;
+};
+
+struct nsgtk_view_menu {
+ GtkMenu *view_menu;
+ GtkImageMenuItem *stop_menuitem;
+ GtkImageMenuItem *reload_menuitem;
+ GtkImageMenuItem *scaleview_menuitem;
+ struct nsgtk_scaleview_submenu *scaleview_submenu;
+ GtkImageMenuItem *fullscreen_menuitem;
+ GtkImageMenuItem *viewsource_menuitem;
+ GtkImageMenuItem *images_menuitem;
+ struct nsgtk_images_submenu *images_submenu;
+ GtkImageMenuItem *toolbars_menuitem;
+ struct nsgtk_toolbars_submenu *toolbars_submenu;
+ GtkImageMenuItem *downloads_menuitem;
+ GtkImageMenuItem *savewindowsize_menuitem;
+ GtkImageMenuItem *debugging_menuitem;
+ struct nsgtk_debugging_submenu *debugging_submenu;
+};
+
+struct nsgtk_nav_menu {
+ GtkMenu *nav_menu;
+ GtkImageMenuItem *back_menuitem;
+ GtkImageMenuItem *forward_menuitem;
+ GtkImageMenuItem *home_menuitem;
+ GtkImageMenuItem *localhistory_menuitem;
+ GtkImageMenuItem *globalhistory_menuitem;
+ GtkImageMenuItem *addbookmarks_menuitem;
+ GtkImageMenuItem *showbookmarks_menuitem;
+ GtkImageMenuItem *openlocation_menuitem;
+};
+
+struct nsgtk_tabs_menu {
+ GtkMenu *tabs_menu;
+ GtkImageMenuItem *nexttab_menuitem;
+ GtkImageMenuItem *prevtab_menuitem;
+ GtkImageMenuItem *closetab_menuitem;
+};
+
+struct nsgtk_help_menu {
+ GtkMenu *help_menu;
+ GtkImageMenuItem *contents_menuitem;
+ GtkImageMenuItem *guide_menuitem;
+ GtkImageMenuItem *info_menuitem;
+ GtkImageMenuItem *about_menuitem;
+};
+
+struct nsgtk_export_submenu {
+ GtkMenu *export_menu;
+ GtkImageMenuItem *plaintext_menuitem;
+ GtkImageMenuItem *drawfile_menuitem;
+ GtkImageMenuItem *postscript_menuitem;
+ GtkImageMenuItem *pdf_menuitem;
+};
+
+struct nsgtk_scaleview_submenu {
+ GtkMenu *scaleview_menu;
+ GtkImageMenuItem *zoomplus_menuitem;
+ GtkImageMenuItem *zoomminus_menuitem;
+ GtkImageMenuItem *zoomnormal_menuitem;
+};
+
+struct nsgtk_images_submenu {
+ GtkMenu *images_menu;
+ GtkCheckMenuItem *foregroundimages_menuitem;
+ GtkCheckMenuItem *backgroundimages_menuitem;
+};
+
+struct nsgtk_toolbars_submenu {
+ GtkMenu *toolbars_menu;
+ GtkCheckMenuItem *menubar_menuitem;
+ GtkCheckMenuItem *toolbar_menuitem;
+ GtkCheckMenuItem *statusbar_menuitem;
+};
+
+struct nsgtk_debugging_submenu {
+ GtkMenu *debugging_menu;
+ GtkImageMenuItem *toggledebugging_menuitem;
+ GtkImageMenuItem *saveboxtree_menuitem;
+ GtkImageMenuItem *savedomtree_menuitem;
+};
+
+struct nsgtk_file_menu *nsgtk_menu_file_menu(GtkAccelGroup *group);
+struct nsgtk_edit_menu *nsgtk_menu_edit_menu(GtkAccelGroup *group);
+struct nsgtk_view_menu *nsgtk_menu_view_menu(GtkAccelGroup *group);
+struct nsgtk_nav_menu *nsgtk_menu_nav_menu(GtkAccelGroup *group);
+struct nsgtk_tabs_menu *nsgtk_menu_tabs_menu(GtkAccelGroup *group);
+struct nsgtk_help_menu *nsgtk_menu_help_menu(GtkAccelGroup *group);
+
+#endif
diff --git a/gtk/gtk_save.c b/gtk/gtk_save.c
new file mode 100644
index 000000000..fc03499ea
--- /dev/null
+++ b/gtk/gtk_save.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <libxml/HTMLtree.h>
+#include "content/content.h"
+#include "desktop/save_complete.h"
+#include "utils/utils.h"
+
+/**
+* conducts the filesystem save appropriate to the gui
+* \param path save path
+* \param filename name of file to save
+* \param len data length
+* \param sourcedata pointer to data to save
+* \param type content type
+* \return true for success
+*/
+
+bool save_complete_gui_save(const char *path, const char *filename,
+ size_t len, const char *sourcedata, content_type type)
+{
+ int res;
+ int namelen;
+ namelen = strlen(path) + strlen(filename) + 2; /* '/', '\0' */
+ char *fullpath = malloc(namelen);
+ if (!fullpath) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ snprintf(fullpath, namelen, "%s/%s", path, filename);
+ FILE *f;
+ f = fopen(fullpath, "wb");
+ free(fullpath);
+ if (f == NULL)
+ return false;
+ res = fwrite(sourcedata, len, 1, f);
+ fclose(f);
+ if (res != 1)
+ return false;
+ return true;
+}
+
+/**
+* wrapper for lib function htmlSaveFileFormat; front sets path from path
+* + filename in a filesystem-specific way
+*/
+
+int save_complete_htmlSaveFileFormat(const char *path, const char *filename,
+ xmlDocPtr cur, const char *encoding, int format)
+{
+ int ret;
+ int len = strlen(path) + strlen(filename) + 2;
+ char *fullpath = malloc(len);
+ if (fullpath == NULL) {
+ warn_user("NoMemory", 0);
+ return -1;
+ }
+ snprintf(fullpath, len, "%s/%s", path, filename);
+ ret = htmlSaveFileFormat(fullpath, cur, encoding, format);
+ free(fullpath);
+ return ret;
+}
+
diff --git a/gtk/gtk_scaffolding.c b/gtk/gtk_scaffolding.c
index 942587c54..01eb2d4e6 100644
--- a/gtk/gtk_scaffolding.c
+++ b/gtk/gtk_scaffolding.c
@@ -1,5 +1,6 @@
/*
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -17,12 +18,16 @@
*/
#include <assert.h>
+#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
#include <libxml/debugXML.h>
+#include "gtk/gtk_scaffolding.h"
#include "content/content.h"
#include "css/utils.h"
#include "desktop/browser.h"
@@ -32,27 +37,37 @@
#include "desktop/options.h"
#include "desktop/plotters.h"
#include "desktop/print.h"
+#include "desktop/save_complete.h"
#ifdef WITH_PDF_EXPORT
#include "desktop/save_pdf/font_haru.h"
#include "desktop/save_pdf/pdf_plotters.h"
#endif
+#include "desktop/save_text.h"
+#include "desktop/search.h"
+#include "desktop/searchweb.h"
#include "desktop/selection.h"
#include "desktop/textinput.h"
#include "gtk/gtk_completion.h"
#include "gtk/dialogs/gtk_options.h"
#include "gtk/dialogs/gtk_about.h"
#include "gtk/dialogs/gtk_source.h"
+#include "gtk/gtk_bitmap.h"
#include "gtk/gtk_download.h"
#include "gtk/gtk_gui.h"
#include "gtk/gtk_history.h"
+#include "gtk/gtk_menu.h"
#include "gtk/gtk_plotters.h"
#include "gtk/gtk_print.h"
-#include "gtk/gtk_scaffolding.h"
#include "gtk/gtk_schedule.h"
+#include "gtk/gtk_search.h"
#include "gtk/gtk_tabs.h"
+#include "gtk/gtk_theme.h"
#include "gtk/gtk_throbber.h"
+#include "gtk/gtk_toolbar.h"
#include "gtk/gtk_window.h"
#include "gtk/options.h"
+#include "gtk/sexy_icon_entry.h"
+#include "image/ico.h"
#include "render/box.h"
#include "render/font.h"
#include "render/form.h"
@@ -63,50 +78,85 @@
#include "utils/log.h"
-struct gtk_history_window;
+struct gtk_scaffolding {
+ GtkWindow *window;
+ GtkNotebook *notebook;
+ GtkWidget *url_bar;
+ GtkEntryCompletion *url_bar_completion;
+ GtkStatusbar *status_bar;
+ struct nsgtk_file_menu *file_menu;
+ struct nsgtk_file_menu *rclick_file_menu;
+ struct nsgtk_edit_menu *edit_menu;
+ struct nsgtk_edit_menu *rclick_edit_menu;
+ struct nsgtk_view_menu *view_menu;
+ struct nsgtk_view_menu *rclick_view_menu;
+ struct nsgtk_nav_menu *nav_menu;
+ struct nsgtk_nav_menu *rclick_nav_menu;
+ struct nsgtk_tabs_menu *tabs_menu;
+ struct nsgtk_tabs_menu *rclick_tabs_menu;
+ struct nsgtk_help_menu *help_menu;
+ struct nsgtk_help_menu *rclick_help_menu;
+ GtkMenuItem *edit_menu_item;
+ GtkMenuItem *tabs_menu_item;
+ GtkToolbar *tool_bar;
+ struct nsgtk_button_connect *buttons[PLACEHOLDER_BUTTON];
+ GtkMenuBar *menu_bar;
+ GtkImage *throbber;
+ GtkImage *icoFav;
+ struct gtk_search *search;
+ GtkImage *webSearchIco;
+ GtkWidget *webSearchEntry;
+ GtkPaned *status_pane;
+
+ int offset;
+ int toolbarmem;
+ int toolbarbase;
+ int historybase;
+
+ GladeXML *xml;
-struct gtk_history_window {
- struct gtk_scaffolding *g;
- GtkWindow *window;
- GtkScrolledWindow *scrolled;
- GtkDrawingArea *drawing_area;
-};
+ GladeXML *popup_xml;
+ GtkMenu *popup_menu;
+
+ struct gtk_history_window *history_window;
+ GtkDialog *preferences_dialog;
+
+ int throb_frame;
+ struct gui_window *top_level;
+ int being_destroyed;
-struct menu_events {
- const char *widget;
- GCallback handler;
+ bool fullscreen;
+
+ /* keep global linked list for gui interface adjustments */
+ struct gtk_scaffolding *next, *prev;
};
static int open_windows = 0; /**< current number of open browsers */
static struct gtk_scaffolding *current_model; /**< current window for model
- dialogue use */
+ dialogue use */
+nsgtk_scaffolding *scaf_list = NULL; /**< global list for interface changes */
static struct box *current_menu_link_box; /**< pointer to the box containing a
link under the mouse, or 0 if none */
-static gboolean nsgtk_window_delete_event(GtkWidget *, gpointer);
-static void nsgtk_window_destroy_event(GtkWidget *, gpointer);
+static gboolean nsgtk_window_delete_event(GtkWidget *, GdkEvent *, gpointer);
+static void nsgtk_window_close(struct gtk_scaffolding *g);
static void nsgtk_window_update_back_forward(struct gtk_scaffolding *);
static void nsgtk_throb(void *);
+static gboolean nsgtk_filter_directory(const GtkFileFilterInfo *info,
+ gpointer data);
static gboolean nsgtk_window_edit_menu_clicked(GtkWidget *widget,
struct gtk_scaffolding *g);
static gboolean nsgtk_window_edit_menu_hidden(GtkWidget *widget,
struct gtk_scaffolding *g);
static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget,
struct gtk_scaffolding *g);
-static gboolean nsgtk_window_back_button_clicked(GtkWidget *, gpointer);
-static gboolean nsgtk_window_history_button_clicked(GtkWidget *, gpointer);
-static gboolean nsgtk_window_forward_button_clicked(GtkWidget *, gpointer);
-static gboolean nsgtk_window_stop_button_clicked(GtkWidget *, gpointer);
-static gboolean nsgtk_window_reload_button_clicked(GtkWidget *, gpointer);
-static gboolean nsgtk_window_home_button_clicked(GtkWidget *, gpointer);
-static gboolean nsgtk_window_url_activate_event(GtkWidget *, gpointer);
-static gboolean nsgtk_window_url_changed(GtkWidget *, GdkEventKey *, gpointer);
-
+static gboolean nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar, gint x,
+ gint y, gint button, gpointer data);
static guint nsgtk_scaffolding_update_link_operations_sensitivity(
struct gtk_scaffolding *g, GladeXML *xml, gdouble x, gdouble y,
gboolean hide);
static guint nsgtk_scaffolding_update_edit_actions_sensitivity(
- struct gtk_scaffolding *g, GladeXML *xml, gboolean hide);
+ struct gtk_scaffolding *g, GladeXML *xml, bool hide);
static void nsgtk_scaffolding_enable_link_operations_sensitivity(
struct gtk_scaffolding *g, GladeXML *xml);
static void nsgtk_scaffolding_enable_edit_actions_sensitivity(
@@ -117,168 +167,69 @@ static gboolean nsgtk_history_expose_event(GtkWidget *, GdkEventExpose *,
static gboolean nsgtk_history_button_press_event(GtkWidget *, GdkEventButton *,
gpointer);
-static void nsgtk_attach_menu_handlers(GladeXML *, gpointer);
+static void nsgtk_attach_menu_handlers(struct gtk_scaffolding *);
static void nsgtk_window_tabs_num_changed(GtkNotebook *notebook,
GtkWidget *page, guint page_num, struct gtk_scaffolding *g);
void nsgtk_openfile_open(const char *filename);
-#define MENUEVENT(x) { #x, G_CALLBACK(nsgtk_on_##x##_activate) }
-#define MENUPROTO(x) static gboolean nsgtk_on_##x##_activate( \
- GtkMenuItem *widget, gpointer g)
-/* prototypes for menu handlers */
-/* file menu */
-MENUPROTO(new_window);
-MENUPROTO(new_tab);
-MENUPROTO(open_location);
-MENUPROTO(open_file);
-#ifdef WITH_PDF_EXPORT
-MENUPROTO(export_pdf);
-#endif
-MENUPROTO(print);
-MENUPROTO(close_window);
-MENUPROTO(quit);
-
-/* edit menu */
-MENUPROTO(cut);
-MENUPROTO(copy);
-MENUPROTO(paste);
-MENUPROTO(select_all);
-MENUPROTO(preferences);
-
-/* view menu */
-MENUPROTO(stop);
-MENUPROTO(reload);
-MENUPROTO(zoom_in);
-MENUPROTO(normal_size);
-MENUPROTO(zoom_out);
-MENUPROTO(full_screen);
-MENUPROTO(view_source);
-MENUPROTO(menu_bar);
-MENUPROTO(tool_bar);
-MENUPROTO(status_bar);
-MENUPROTO(downloads);
-MENUPROTO(save_window_size);
-MENUPROTO(toggle_debug_rendering);
-MENUPROTO(save_box_tree);
-MENUPROTO(save_dom_tree);
-
-/* navigate menu */
-MENUPROTO(back);
-MENUPROTO(forward);
-MENUPROTO(home);
-MENUPROTO(local_history);
-MENUPROTO(global_history);
-
-/* tabs menu */
-MENUPROTO(next_tab);
-MENUPROTO(prev_tab);
-MENUPROTO(close_tab);
-
-/* help menu */
-MENUPROTO(about);
-
-/* Popup context menu (also shares edit menu handlers) */
-MENUPROTO(save_link);
-MENUPROTO(open_link_in_focused_tab);
-MENUPROTO(open_link_in_background_tab);
-
-/* structure used by nsgtk_attach_menu_handlers to connect menu items to
- * their handling functions.
- */
-static struct menu_events menu_events[] = {
- /* file menu */
- MENUEVENT(new_window),
- MENUEVENT(new_tab),
- MENUEVENT(open_location),
- MENUEVENT(open_file),
-#ifdef WITH_PDF_EXPORT
- MENUEVENT(export_pdf),
-#endif
- MENUEVENT(print),
- MENUEVENT(close_window),
- MENUEVENT(quit),
-
- /* edit menu */
- MENUEVENT(cut),
- MENUEVENT(copy),
- MENUEVENT(paste),
- MENUEVENT(select_all),
- MENUEVENT(preferences),
-
- /* view menu */
- MENUEVENT(stop),
- MENUEVENT(reload),
- MENUEVENT(zoom_in),
- MENUEVENT(normal_size),
- MENUEVENT(zoom_out),
- MENUEVENT(full_screen),
- MENUEVENT(view_source),
- MENUEVENT(menu_bar),
- MENUEVENT(tool_bar),
- MENUEVENT(status_bar),
- MENUEVENT(downloads),
- MENUEVENT(save_window_size),
- MENUEVENT(toggle_debug_rendering),
- MENUEVENT(save_box_tree),
- MENUEVENT(save_dom_tree),
-
- /* navigate menu */
- MENUEVENT(back),
- MENUEVENT(forward),
- MENUEVENT(home),
- MENUEVENT(local_history),
- MENUEVENT(global_history),
-
- /* tab menu */
- MENUEVENT(next_tab),
- MENUEVENT(prev_tab),
- MENUEVENT(close_tab),
-
- /* help menu */
- MENUEVENT(about),
-
- /* sentinel */
- { NULL, NULL }
-};
-
-void nsgtk_attach_menu_handlers(GladeXML *xml, gpointer g)
+void nsgtk_attach_menu_handlers(struct gtk_scaffolding *g)
{
- struct menu_events *event = menu_events;
-
- while (event->widget != NULL)
- {
- GtkWidget *w = glade_xml_get_widget(xml, event->widget);
- g_signal_connect(G_OBJECT(w), "activate", event->handler, g);
- event++;
+ for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ if (g->buttons[i]->main != NULL) {
+ g_signal_connect(g->buttons[i]->main, "activate",
+ G_CALLBACK(g->buttons[i]->mhandler), g);
+ }
+ if (g->buttons[i]->rclick != NULL) {
+ g_signal_connect(g->buttons[i]->rclick, "activate",
+ G_CALLBACK(g->buttons[i]->mhandler), g);
+ }
+ if (g->buttons[i]->popup != NULL) {
+ g_signal_connect(g->buttons[i]->popup, "activate",
+ G_CALLBACK(g->buttons[i]->mhandler), g);
+ }
}
-}
+#define CONNECT_CHECK(q)\
+ g_signal_connect(g->view_menu->toolbars_submenu->q##_menuitem,\
+ "toggled", G_CALLBACK(nsgtk_on_##q##_activate), g);\
+ g_signal_connect(g->rclick_view_menu->toolbars_submenu->q##_menuitem,\
+ "toggled", G_CALLBACK(nsgtk_on_##q##_activate), g)
+ CONNECT_CHECK(menubar);
+ CONNECT_CHECK(toolbar);
+ CONNECT_CHECK(statusbar);
+#undef CONNECT_CHECK
-GtkWindow *nsgtk_get_window_for_scaffold(struct gtk_scaffolding *g)
-{
- return g->window;
}
/* event handlers and support functions for them */
-gboolean nsgtk_window_delete_event(GtkWidget *widget, gpointer data)
+gboolean nsgtk_window_delete_event(GtkWidget *widget, GdkEvent *event, gpointer
+ data)
{
- struct gtk_scaffolding *g = data;
- gtk_widget_destroy(GTK_WIDGET(g->window));
- if (open_windows == 1 && nsgtk_check_for_downloads(GTK_WINDOW(widget)))
- return TRUE;
- else
- return FALSE;
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ if (open_windows != 1 || nsgtk_check_for_downloads(GTK_WINDOW(
+ widget)) == false) {
+ nsgtk_window_close(g);
+ gtk_widget_destroy(GTK_WIDGET(g->window));
+ }
+ return TRUE;
}
-void nsgtk_window_destroy_event(GtkWidget *widget, gpointer data)
+/**
+ * cleanup function
+ */
+void nsgtk_window_close(struct gtk_scaffolding *g)
{
- struct gtk_scaffolding *g = data;
+ /* close all tabs first */
+ gint numbertabs = gtk_notebook_get_n_pages(g->notebook);
+ while (numbertabs-- > 1) {
+ nsgtk_tab_close_current(g->notebook);
+ }
LOG(("Being Destroyed = %d", g->being_destroyed));
- if (g->history_window->window) {
+
+ if ((g->history_window) && (g->history_window->window)) {
gtk_widget_destroy(GTK_WIDGET(g->history_window->window));
}
- gtk_widget_destroy(GTK_WIDGET(g->window));
-
+
if (--open_windows == 0)
netsurf_quit = true;
@@ -286,37 +237,37 @@ void nsgtk_window_destroy_event(GtkWidget *widget, gpointer data)
g->being_destroyed = 1;
nsgtk_window_destroy_browser(g->top_level);
}
+ if (g->prev != NULL)
+ g->prev->next = g->next;
+ else
+ scaf_list = g->next;
+
+ if (g->next != NULL)
+ g->next->prev = g->prev;
+
}
-void nsgtk_scaffolding_destroy(nsgtk_scaffolding *scaffold)
+void nsgtk_scaffolding_destroy(nsgtk_scaffolding *g)
{
/* Our top_level has asked us to die */
- LOG(("Being Destroyed = %d", scaffold->being_destroyed));
- if (scaffold->being_destroyed) return;
- scaffold->being_destroyed = 1;
- nsgtk_window_destroy_event(0, scaffold);
+ LOG(("Being Destroyed = %d", g->being_destroyed));
+ if (g->being_destroyed) return;
+ g->being_destroyed = 1;
+ nsgtk_window_close(g);
}
void nsgtk_window_update_back_forward(struct gtk_scaffolding *g)
{
int width, height;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
-
- gtk_widget_set_sensitive(GTK_WIDGET(g->back_button),
- history_back_available(bw->history));
- gtk_widget_set_sensitive(GTK_WIDGET(g->forward_button),
- history_forward_available(bw->history));
-
- gtk_widget_set_sensitive(GTK_WIDGET(g->back_menu),
- history_back_available(bw->history));
- gtk_widget_set_sensitive(GTK_WIDGET(g->forward_menu),
- history_forward_available(bw->history));
- gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(g->popup_xml,
- "popupBack")), history_back_available(bw->history));
- gtk_widget_set_sensitive(GTK_WIDGET(glade_xml_get_widget(g->popup_xml,
- "popupForward")),
- history_forward_available(bw->history));
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+
+ g->buttons[BACK_BUTTON]->sensitivity =
+ history_back_available(bw->history);
+ g->buttons[FORWARD_BUTTON]->sensitivity = history_forward_available(
+ bw->history);
+
+ nsgtk_scaffolding_set_sensitivity(g);
/* update the url bar, particularly necessary when tabbing */
if (bw->current_content != NULL && bw->current_content->url != NULL)
@@ -351,7 +302,7 @@ void nsgtk_throb(void *p)
static gboolean nsgtk_window_edit_menu_clicked(GtkWidget *widget,
struct gtk_scaffolding *g)
{
- nsgtk_scaffolding_update_edit_actions_sensitivity (g, g->xml, FALSE);
+ nsgtk_scaffolding_update_edit_actions_sensitivity(g, g->xml, false);
return TRUE;
}
@@ -371,97 +322,20 @@ static gboolean nsgtk_window_popup_menu_hidden(GtkWidget *widget,
return TRUE;
}
-gboolean nsgtk_window_back_button_clicked(GtkWidget *widget, gpointer data)
-{
- struct gtk_scaffolding *g = data;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
-
- if (!history_back_available(bw->history))
- return TRUE;
-
- history_back(bw, bw->history);
- nsgtk_window_update_back_forward(g);
-
- return TRUE;
-}
-
-/* TODO: add resize handling */
-gboolean nsgtk_window_history_button_clicked(GtkWidget *widget, gpointer data)
-{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)data;
-
- /* if entries of the same url but different frag_ids have been added
- * the history needs redrawing (what is done in the throbber code in
- * other cases)
- */
- nsgtk_window_update_back_forward(gw);
-
- gtk_window_set_default_size(gw->history_window->window, 500, 150);
- gtk_window_set_position(gw->history_window->window, GTK_WIN_POS_MOUSE);
- gtk_window_set_transient_for(gw->history_window->window, gw->window);
- gtk_window_set_opacity(gw->history_window->window, 0.9);
- gtk_widget_show(GTK_WIDGET(gw->history_window->window));
- gdk_window_raise(GTK_WIDGET(gw->history_window->window)->window);
-
- return TRUE;
-}
-
-gboolean nsgtk_window_forward_button_clicked(GtkWidget *widget, gpointer data)
-{
- struct gtk_scaffolding *g = data;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
-
- if (!history_forward_available(bw->history))
- return TRUE;
-
- history_forward(bw, bw->history);
- nsgtk_window_update_back_forward(g);
-
- return TRUE;
-}
-
-gboolean nsgtk_window_stop_button_clicked(GtkWidget *widget, gpointer data)
-{
- struct gtk_scaffolding *g = data;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
-
- browser_window_stop(bw);
-
- return TRUE;
-}
-
-gboolean nsgtk_window_reload_button_clicked(GtkWidget *widget, gpointer data)
-{
- struct gtk_scaffolding *g = data;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
-
- browser_window_reload(bw, true);
-
- return TRUE;
-}
-
-gboolean nsgtk_window_home_button_clicked(GtkWidget *widget, gpointer data)
-{
- struct gtk_scaffolding *g = data;
- static const char *addr = NETSURF_HOMEPAGE;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
-
- if (option_homepage_url != NULL && option_homepage_url[0] != '\0')
- addr = option_homepage_url;
-
- browser_window_go(bw, addr, 0, true);
-
- return TRUE;
-}
-
gboolean nsgtk_window_url_activate_event(GtkWidget *widget, gpointer data)
{
struct gtk_scaffolding *g = data;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
-
- browser_window_go(bw, gtk_entry_get_text(GTK_ENTRY(g->url_bar)),
- 0, true);
-
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ char *url;
+ if (search_is_url(gtk_entry_get_text(GTK_ENTRY(g->url_bar)))
+ == false)
+ url = search_web_from_term(gtk_entry_get_text(GTK_ENTRY(
+ g->url_bar)));
+ else
+ url = strdup(gtk_entry_get_text(GTK_ENTRY(g->url_bar)));
+ browser_window_go(bw, url, 0, true);
+ if (url != NULL)
+ free(url);
return TRUE;
}
@@ -477,69 +351,107 @@ gboolean nsgtk_window_url_changed(GtkWidget *widget, GdkEventKey *event,
return TRUE;
}
+gboolean nsgtk_window_tool_bar_clicked(GtkToolbar *toolbar, gint x, gint y,
+ gint button, gpointer data)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ /* set visibility for right-click menu */
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml, "sep2"));
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml, "save_link_popup"));
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml,
+ "open_link_in_focused_tab_popup"));
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml,
+ "open_link_in_background_tab_popup"));
+ gtk_widget_show(glade_xml_get_widget(g->popup_xml, "customize_popup"));
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml, "copy_popup"));
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml, "cut_popup"));
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml, "paste_popup"));
+ gtk_menu_popup(g->popup_menu, NULL, NULL, NULL, NULL, 0,
+ gtk_get_current_event_time());
+ return TRUE;
+}
void nsgtk_window_tabs_num_changed(GtkNotebook *notebook, GtkWidget *page,
guint page_num, struct gtk_scaffolding *g)
{
gboolean visible = gtk_notebook_get_show_tabs(g->notebook);
- g_object_set(g->tabs_menu, "visible", visible, NULL);
+ g_object_set(g->tabs_menu_item, "visible", visible, NULL);
+ g->buttons[NEXTTAB_BUTTON]->sensitivity = visible;
+ g->buttons[PREVTAB_BUTTON]->sensitivity = visible;
+ g->buttons[CLOSETAB_BUTTON]->sensitivity = visible;
+ nsgtk_scaffolding_set_sensitivity(g);
}
void nsgtk_openfile_open(const char *filename)
{
- struct browser_window *bw = nsgtk_get_browser_for_gui(
+ struct browser_window *bw = gui_window_get_browser_window(
current_model->top_level);
- char *url = malloc(strlen(filename) + sizeof("file://"));
+ char url[strlen(filename) + SLEN("file://") + 1];
sprintf(url, "file://%s", filename);
browser_window_go(bw, url, 0, true);
- free(url);
}
/* signal handlers for menu entries */
-#define MENUHANDLER(x) gboolean nsgtk_on_##x##_activate(GtkMenuItem *widget, \
- gpointer g)
-
-MENUHANDLER(new_window)
-{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
- const char *url = gtk_entry_get_text(GTK_ENTRY(gw->url_bar));
+#define MULTIHANDLER(q)\
+gboolean nsgtk_on_##q##_activate_menu(GtkMenuItem *widget, gpointer data)\
+{\
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;\
+ return nsgtk_on_##q##_activate(g);\
+}\
+gboolean nsgtk_on_##q##_activate_button(GtkButton *widget, gpointer data)\
+{\
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;\
+ return nsgtk_on_##q##_activate(g);\
+}\
+gboolean nsgtk_on_##q##_activate(struct gtk_scaffolding *g)
+
+#define MENUHANDLER(q)\
+gboolean nsgtk_on_##q##_activate(GtkMenuItem *widget, gpointer data)
+
+#define BUTTONHANDLER(q)\
+gboolean nsgtk_on_##q##_activate(GtkButton *widget, gpointer data)
+
+MULTIHANDLER(newwindow)
+{
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ const char *url = gtk_entry_get_text(GTK_ENTRY(g->url_bar));
browser_window_create(url, bw, NULL, false, false);
return TRUE;
}
-MENUHANDLER(new_tab)
+MULTIHANDLER(newtab)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
- const char *url = gtk_entry_get_text(GTK_ENTRY(gw->url_bar));
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ const char *url = gtk_entry_get_text(GTK_ENTRY(g->url_bar));
- if (option_new_blank)
+ if (option_new_blank) {
browser_window_create(0, bw, NULL, false, true);
-
+ GtkWidget *window = gtk_notebook_get_nth_page(g->notebook, -1);
+ gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &((GdkColor)
+ {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}));
+ }
+
else
browser_window_create(url, bw, NULL, false, true);
return TRUE;
}
-MENUHANDLER(open_location)
+MULTIHANDLER(open_location)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
- gtk_widget_grab_focus(GTK_WIDGET(gw->url_bar));
+ gtk_widget_grab_focus(GTK_WIDGET(g->url_bar));
return TRUE;
}
-MENUHANDLER(open_file)
+MULTIHANDLER(openfile)
{
- current_model = (struct gtk_scaffolding *)g;
+ current_model = g;
GtkWidget *dlgOpen = gtk_file_chooser_dialog_new("Open File",
current_model->window, GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, -6, GTK_STOCK_OPEN, -5, NULL);
@@ -558,12 +470,76 @@ MENUHANDLER(open_file)
return TRUE;
}
-#ifdef WITH_PDF_EXPORT
-MENUHANDLER(export_pdf)
+MULTIHANDLER(savepage)
+{
+ if (gui_window_get_browser_window(g->top_level)->current_content
+ == NULL)
+ return FALSE;
+
+ GtkWidget *fc = gtk_file_chooser_dialog_new(
+ messages_get("gtkcompleteSave"), g->window,
+ GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT,
+ NULL);
+ DIR *d;
+ char *path;
+ url_func_result res;
+ GtkFileFilter *filter = gtk_file_filter_new();
+ gtk_file_filter_set_name(filter, "directory");
+ gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME,
+ nsgtk_filter_directory, NULL, NULL);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fc), filter);
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fc), filter);
+
+ res = url_nice(gui_window_get_browser_window(
+ g->top_level)->current_content->url, &path, false);
+ if (res != URL_FUNC_OK) {
+ path = strdup(messages_get("SaveText"));
+ if (path == NULL) {
+ warn_user("NoMemory", 0);
+ return FALSE;
+ }
+ }
+
+ if (access(path, F_OK) != 0)
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), path);
+ free(path);
+
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fc),
+ TRUE);
+
+ if (gtk_dialog_run(GTK_DIALOG(fc)) != GTK_RESPONSE_ACCEPT)
+ return TRUE;
+ path = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
+ d = opendir(path);
+ if (d == NULL) {
+ printf("d NULL\n");
+ if (errno == ENOTDIR)
+ warn_user("NoDirError", path);
+ else
+ warn_user("gtkFileError", path);
+ g_free(path);
+ return TRUE;
+ }
+ closedir(d);
+ save_complete_init();
+ save_complete(gui_window_get_browser_window(
+ g->top_level)->current_content, path);
+ g_free(path);
+
+ gtk_widget_destroy(fc);
+
+ return TRUE;
+}
+
+
+MULTIHANDLER(pdf)
{
+#ifdef WITH_PDF_EXPORT
+
GtkWidget *save_dialog;
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
struct print_settings *settings;
char filename[PATH_MAX];
char dirname[PATH_MAX];
@@ -593,7 +569,7 @@ MENUHANDLER(export_pdf)
used by the all-purpose print interface*/
haru_nsfont_set_scale((float)option_export_scale / 100);
- save_dialog = gtk_file_chooser_dialog_new("Export to PDF", gw->window,
+ save_dialog = gtk_file_chooser_dialog_new("Export to PDF", g->window,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
@@ -625,14 +601,72 @@ MENUHANDLER(export_pdf)
gtk_widget_destroy(save_dialog);
+#endif /* WITH_PDF_EXPORT */
+
return TRUE;
}
-#endif /* WITH_PDF_EXPORT */
-MENUHANDLER(print)
+MULTIHANDLER(plaintext)
+{
+ if (gui_window_get_browser_window(g->top_level)->current_content
+ == NULL)
+ return FALSE;
+
+ GtkWidget *fc = gtk_file_chooser_dialog_new(
+ messages_get("gtkplainSave"), g->window,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ char *filename;
+ url_func_result res;
+
+ res = url_nice(gui_window_get_browser_window(
+ g->top_level)->current_content->url, &filename, false);
+ if (res != URL_FUNC_OK) {
+ filename = strdup(messages_get("SaveText"));
+ if (filename == NULL) {
+ warn_user("NoMemory", 0);
+ return FALSE;
+ }
+ }
+
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fc), filename);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(fc),
+ TRUE);
+
+ free(filename);
+
+ if (gtk_dialog_run(GTK_DIALOG(fc)) == GTK_RESPONSE_ACCEPT) {
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc));
+ save_as_text(gui_window_get_browser_window(
+ g->top_level)->current_content, filename);
+ g_free(filename);
+ }
+
+ gtk_widget_destroy(fc);
+ return TRUE;
+}
+
+MULTIHANDLER(drawfile)
+{
+ return TRUE;
+}
+
+MULTIHANDLER(postscript)
+{
+ return TRUE;
+}
+
+MULTIHANDLER(printpreview)
+{
+ return TRUE;
+}
+
+
+MULTIHANDLER(print)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
GtkPrintOperation *print_op;
GtkPageSetup *page_setup;
@@ -659,7 +693,7 @@ MENUHANDLER(print)
content_to_print = bw->current_content;
- page_setup = gtk_print_run_page_setup_dialog(gw->window, NULL, NULL);
+ page_setup = gtk_print_run_page_setup_dialog(g->window, NULL, NULL);
if (page_setup == NULL) {
warn_user(messages_get("NoMemory"), 0);
g_object_unref(print_op);
@@ -678,7 +712,7 @@ MENUHANDLER(print)
if (bw->current_content->type != CONTENT_TEXTPLAIN)
res = gtk_print_operation_run(print_op,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
- gw->window,
+ g->window,
NULL);
/* if the settings were used save them for future use */
@@ -698,50 +732,46 @@ MENUHANDLER(print)
return TRUE;
}
-MENUHANDLER(close_window)
+MULTIHANDLER(closewindow)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
/* close all tabs first */
- gint numbertabs = gtk_notebook_get_n_pages(gw->notebook);
+ gint numbertabs = gtk_notebook_get_n_pages(g->notebook);
while (numbertabs-- > 1) {
- nsgtk_tab_close_current(gw->notebook);
+ nsgtk_tab_close_current(g->notebook);
}
- gtk_widget_destroy(GTK_WIDGET(gw->window));
-
+ nsgtk_window_close(g);
+ gtk_widget_destroy(GTK_WIDGET(g->window));
return TRUE;
}
-MENUHANDLER(quit)
+MULTIHANDLER(quit)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
- if (nsgtk_check_for_downloads(gw->window) == false)
+ if (nsgtk_check_for_downloads(g->window) == false)
netsurf_quit = true;
return TRUE;
}
-MENUHANDLER(save_link)
+MENUHANDLER(savelink)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct gui_window *gui = gw->top_level;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gui);
-
- if (!current_menu_link_box)
- return FALSE;
-
- browser_window_download(bw, current_menu_link_box->href,
- bw->current_content->url);
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *) data;
+ struct gui_window *gui = g->top_level;
+ struct browser_window *bw = gui_window_get_browser_window(gui);
+
+ if (!current_menu_link_box)
+ return FALSE;
+
+ browser_window_download(bw, current_menu_link_box->href,
+ bw->current_content->url);
- return TRUE;
+ return TRUE;
}
-MENUHANDLER(open_link_in_focused_tab)
+MENUHANDLER(linkfocused)
{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *) data;
temp_open_background = 0;
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct gui_window *gui = gw->top_level;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gui);
+ struct gui_window *gui = g->top_level;
+ struct browser_window *bw = gui_window_get_browser_window(gui);
if (current_menu_link_box == NULL)
return FALSE;
@@ -753,11 +783,11 @@ MENUHANDLER(open_link_in_focused_tab)
return TRUE;
}
-MENUHANDLER(open_link_in_background_tab)
+MENUHANDLER(linkbackground)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct gui_window *gui = gw->top_level;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gui);
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *) data;
+ struct gui_window *gui = g->top_level;
+ struct browser_window *bw = gui_window_get_browser_window(gui);
temp_open_background = 1;
@@ -772,41 +802,38 @@ MENUHANDLER(open_link_in_background_tab)
}
-MENUHANDLER(cut)
+MULTIHANDLER(cut)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
- GtkWidget *focused = gtk_window_get_focus(gw->window);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ GtkWidget *focused = gtk_window_get_focus(g->window);
/* If the url bar has focus, let gtk handle it */
if (GTK_IS_EDITABLE (focused))
- gtk_editable_cut_clipboard (GTK_EDITABLE(gw->url_bar));
+ gtk_editable_cut_clipboard (GTK_EDITABLE(g->url_bar));
else
browser_window_key_press(bw, KEY_CUT_SELECTION);
return TRUE;
}
-MENUHANDLER(copy)
+MULTIHANDLER(copy)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
- GtkWidget *focused = gtk_window_get_focus(gw->window);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ GtkWidget *focused = gtk_window_get_focus(g->window);
/* If the url bar has focus, let gtk handle it */
if (GTK_IS_EDITABLE (focused))
- gtk_editable_copy_clipboard(GTK_EDITABLE(gw->url_bar));
+ gtk_editable_copy_clipboard(GTK_EDITABLE(g->url_bar));
else
gui_copy_to_clipboard(bw->sel);
return TRUE;
}
-MENUHANDLER(paste)
+MULTIHANDLER(paste)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct gui_window *gui = gw->top_level;
- GtkWidget *focused = gtk_window_get_focus(gw->window);
+ struct gui_window *gui = g->top_level;
+ GtkWidget *focused = gtk_window_get_focus(g->window);
/* If the url bar has focus, let gtk handle it */
if (GTK_IS_EDITABLE (focused))
@@ -817,14 +844,25 @@ MENUHANDLER(paste)
return TRUE;
}
-MENUHANDLER(select_all)
+MULTIHANDLER(delete)
+{
+ return TRUE;
+}
+
+MENUHANDLER(customize)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ nsgtk_toolbar_customization_init(g);
+ return TRUE;
+}
+
+MULTIHANDLER(selectall)
+{
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
- if (GTK_WIDGET_HAS_FOCUS(gw->url_bar)) {
+ if (GTK_WIDGET_HAS_FOCUS(g->url_bar)) {
LOG(("Selecting all URL bar text"));
- gtk_editable_select_region(GTK_EDITABLE(gw->url_bar), 0, -1);
+ gtk_editable_select_region(GTK_EDITABLE(g->url_bar), 0, -1);
} else {
LOG(("Selecting all document text"));
selection_select_all(bw->sel);
@@ -833,145 +871,213 @@ MENUHANDLER(select_all)
return TRUE;
}
-MENUHANDLER(preferences)
+MULTIHANDLER(find)
+{
+ nsgtk_scaffolding_toggle_search_bar_visibility(g);
+ return TRUE;
+}
+
+MULTIHANDLER(preferences)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
- if (gw->preferences_dialog == NULL)
- gw->preferences_dialog = nsgtk_options_init(bw, gw->window);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ if (g->preferences_dialog == NULL)
+ g->preferences_dialog = nsgtk_options_init(bw, g->window);
else
- gtk_widget_show (GTK_WIDGET(gw->preferences_dialog));
+ gtk_widget_show(GTK_WIDGET(g->preferences_dialog));
return TRUE;
}
-MENUHANDLER(zoom_in)
+MULTIHANDLER(zoomplus)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
- float old_scale = nsgtk_get_scale_for_gui(gw->top_level);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ float old_scale = nsgtk_get_scale_for_gui(g->top_level);
browser_window_set_scale(bw, old_scale + 0.05, true);
return TRUE;
}
-MENUHANDLER(normal_size)
+MULTIHANDLER(zoomnormal)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
browser_window_set_scale(bw, 1.0, true);
return TRUE;
}
-MENUHANDLER(zoom_out)
+MULTIHANDLER(zoomminus)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- struct browser_window *bw = nsgtk_get_browser_for_gui(gw->top_level);
- float old_scale = nsgtk_get_scale_for_gui(gw->top_level);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
+ float old_scale = nsgtk_get_scale_for_gui(g->top_level);
browser_window_set_scale(bw, old_scale - 0.05, true);
return TRUE;
}
-MENUHANDLER(full_screen)
+MULTIHANDLER(fullscreen)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
- if (gw->fullscreen) {
- gtk_window_unfullscreen(gw->window);
+ if (g->fullscreen) {
+ gtk_window_unfullscreen(g->window);
} else {
- gtk_window_fullscreen(gw->window);
+ gtk_window_fullscreen(g->window);
}
- gw->fullscreen = !gw->fullscreen;
+ g->fullscreen = !g->fullscreen;
return TRUE;
}
-MENUHANDLER(view_source)
+MULTIHANDLER(viewsource)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- nsgtk_source_dialog_init(gw->window,
- nsgtk_get_browser_for_gui(gw->top_level));
+ nsgtk_source_dialog_init(g->window,
+ gui_window_get_browser_window(g->top_level));
return TRUE;
}
-MENUHANDLER(menu_bar)
+MENUHANDLER(menubar)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
+ GtkWidget *w;
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
- gtk_widget_show(GTK_WIDGET(gw->menu_bar));
+ /* need to synchronise menus as gtk grumbles when one menu
+ * is attached to both headers */
+ w = GTK_WIDGET(g->rclick_view_menu->
+ toolbars_submenu->menubar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))
+ == FALSE)
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ TRUE);
+ w = GTK_WIDGET(g->view_menu->
+ toolbars_submenu->menubar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))
+ == FALSE)
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ TRUE);
- gtk_widget_show_all(GTK_WIDGET(gw->popup_menu));
-
- GList *widgets = glade_xml_get_widget_prefix(gw->popup_xml,
+ gtk_widget_show(GTK_WIDGET(g->menu_bar));
+
+ gtk_widget_show_all(GTK_WIDGET(g->popup_menu));
+
+ GList *widgets = glade_xml_get_widget_prefix(g->popup_xml,
"menupopup");
for (; widgets != NULL; widgets = widgets->next)
gtk_widget_hide(GTK_WIDGET(widgets->data));
+
} else {
- gtk_widget_hide(GTK_WIDGET(gw->menu_bar));
+ w = GTK_WIDGET(g->rclick_view_menu->
+ toolbars_submenu->menubar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ FALSE);
+ w = GTK_WIDGET(g->view_menu->
+ toolbars_submenu->menubar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ FALSE);
- gtk_widget_hide_all(GTK_WIDGET(gw->popup_menu));
- gtk_widget_show(GTK_WIDGET(gw->popup_menu));
+ gtk_widget_hide(GTK_WIDGET(g->menu_bar));
- GList *widgets = glade_xml_get_widget_prefix(gw->popup_xml,
+ GList *widgets = glade_xml_get_widget_prefix(g->popup_xml,
"menupopup");
for (; widgets != NULL; widgets = widgets->next)
gtk_widget_show_all(GTK_WIDGET(widgets->data));
- }
+ }
return TRUE;
}
-MENUHANDLER(tool_bar)
+MENUHANDLER(toolbar)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
+ GtkWidget *w;
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
- gtk_widget_show(GTK_WIDGET(gw->tool_bar));
+ w = GTK_WIDGET(g->rclick_view_menu->
+ toolbars_submenu->toolbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))
+ == FALSE)
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ TRUE);
+ w = GTK_WIDGET(g->view_menu->
+ toolbars_submenu->toolbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))
+ == FALSE)
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ TRUE);
+ gtk_widget_show(GTK_WIDGET(g->tool_bar));
} else {
- gtk_widget_hide(GTK_WIDGET(gw->tool_bar));
+ w = GTK_WIDGET(g->rclick_view_menu->
+ toolbars_submenu->toolbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ FALSE);
+ w = GTK_WIDGET(g->view_menu->
+ toolbars_submenu->toolbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ FALSE);
+ gtk_widget_hide(GTK_WIDGET(g->tool_bar));
}
return TRUE;
}
-MENUHANDLER(status_bar)
+MENUHANDLER(statusbar)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
+ GtkWidget *w;
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
- gtk_widget_show(GTK_WIDGET(gw->status_bar));
+ w = GTK_WIDGET(g->rclick_view_menu->
+ toolbars_submenu->statusbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))
+ == FALSE)
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ TRUE);
+ w = GTK_WIDGET(g->view_menu->
+ toolbars_submenu->statusbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))
+ == FALSE)
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ TRUE);
+ gtk_widget_show(GTK_WIDGET(g->status_bar));
} else {
- gtk_widget_hide(GTK_WIDGET(gw->status_bar));
+ w = GTK_WIDGET(g->rclick_view_menu->
+ toolbars_submenu->statusbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ FALSE);
+ w = GTK_WIDGET(g->view_menu->
+ toolbars_submenu->statusbar_menuitem);
+ if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w)))
+ gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(w),
+ FALSE);
+ gtk_widget_hide(GTK_WIDGET(g->status_bar));
}
return TRUE;
}
-MENUHANDLER(downloads)
+MULTIHANDLER(downloads)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- nsgtk_download_show(gw->window);
+ nsgtk_download_show(g->window);
return TRUE;
}
-MENUHANDLER(save_window_size)
+MULTIHANDLER(savewindowsize)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
-
- option_toolbar_status_width = gtk_paned_get_position(gw->status_pane);
- gtk_window_get_position(gw->window, &option_window_x,
+ if (GTK_IS_PANED(g->status_pane))
+ option_toolbar_status_width =
+ gtk_paned_get_position(g->status_pane);
+ gtk_window_get_position(g->window, &option_window_x,
&option_window_y);
- gtk_window_get_size(gw->window, &option_window_width,
+ gtk_window_get_size(g->window, &option_window_width,
&option_window_height);
@@ -980,19 +1086,18 @@ MENUHANDLER(save_window_size)
return TRUE;
}
-MENUHANDLER(toggle_debug_rendering)
+MULTIHANDLER(toggledebugging)
{
html_redraw_debug = !html_redraw_debug;
nsgtk_reflow_all_windows();
return TRUE;
}
-MENUHANDLER(save_box_tree)
+MULTIHANDLER(saveboxtree)
{
GtkWidget *save_dialog;
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- save_dialog = gtk_file_chooser_dialog_new("Save File", gw->window,
+ save_dialog = gtk_file_chooser_dialog_new("Save File", g->window,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
@@ -1017,7 +1122,7 @@ MENUHANDLER(save_box_tree)
"Unable to open file for writing.");
} else {
struct browser_window *bw;
- bw = nsgtk_get_browser_window(gw->top_level);
+ bw = gui_window_get_browser_window(g->top_level);
if (bw->current_content &&
bw->current_content->type ==
@@ -1038,12 +1143,11 @@ MENUHANDLER(save_box_tree)
return TRUE;
}
-MENUHANDLER(save_dom_tree)
+MULTIHANDLER(savedomtree)
{
GtkWidget *save_dialog;
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- save_dialog = gtk_file_chooser_dialog_new("Save File", gw->window,
+ save_dialog = gtk_file_chooser_dialog_new("Save File", g->window,
GTK_FILE_CHOOSER_ACTION_SAVE,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
@@ -1067,7 +1171,7 @@ MENUHANDLER(save_dom_tree)
"Unable to open file for writing.");
} else {
struct browser_window *bw;
- bw = nsgtk_get_browser_window(gw->top_level);
+ bw = gui_window_get_browser_window(g->top_level);
if (bw->current_content &&
bw->current_content->type ==
@@ -1089,37 +1193,119 @@ MENUHANDLER(save_dom_tree)
}
-MENUHANDLER(stop)
+MULTIHANDLER(stop)
{
- return nsgtk_window_stop_button_clicked(GTK_WIDGET(widget), g);
+ struct browser_window *bw =
+ gui_window_get_browser_window(g->top_level);
+
+ browser_window_stop(bw);
+
+ return TRUE;
}
-MENUHANDLER(reload)
+MULTIHANDLER(reload)
{
- return nsgtk_window_reload_button_clicked(GTK_WIDGET(widget), g);
+ struct browser_window *bw =
+ gui_window_get_browser_window(g->top_level);
+
+ /* clear potential search effects */
+
+ if ((bw != NULL) && (bw->search_context != NULL))
+ search_destroy_context(bw->search_context);
+ nsgtk_search_set_forward_state(true, bw);
+ nsgtk_search_set_back_state(true, bw);
+
+ browser_window_reload(bw, true);
+
+ return TRUE;
}
-MENUHANDLER(back)
+MULTIHANDLER(back)
{
- return nsgtk_window_back_button_clicked(GTK_WIDGET(widget), g);
+ struct browser_window *bw =
+ gui_window_get_browser_window(g->top_level);
+
+ if (!history_back_available(bw->history))
+ return TRUE;
+
+ /* clear potential search effects */
+ if ((bw != NULL) && (bw->search_context != NULL))
+ search_destroy_context(bw->search_context);
+ nsgtk_search_set_forward_state(true, bw);
+ nsgtk_search_set_back_state(true, bw);
+
+ history_back(bw, bw->history);
+ nsgtk_window_update_back_forward(g);
+
+ return TRUE;
}
-MENUHANDLER(forward)
+MULTIHANDLER(forward)
{
- return nsgtk_window_forward_button_clicked(GTK_WIDGET(widget), g);
+ struct browser_window *bw =
+ gui_window_get_browser_window(g->top_level);
+
+ if (!history_forward_available(bw->history))
+ return TRUE;
+
+ /* clear potential search effects */
+ if ((bw != NULL) && (bw->search_context != NULL))
+ search_destroy_context(bw->search_context);
+ nsgtk_search_set_forward_state(true, bw);
+ nsgtk_search_set_back_state(true, bw);
+
+ history_forward(bw, bw->history);
+ nsgtk_window_update_back_forward(g);
+
+ return TRUE;
}
-MENUHANDLER(home)
+MULTIHANDLER(home)
{
- return nsgtk_window_home_button_clicked(GTK_WIDGET(widget), g);
+ static const char *addr = NETSURF_HOMEPAGE;
+ struct browser_window *bw =
+ gui_window_get_browser_window(g->top_level);
+
+ if (option_homepage_url != NULL && option_homepage_url[0] != '\0')
+ addr = option_homepage_url;
+
+ browser_window_go(bw, addr, 0, true);
+
+ return TRUE;
}
-MENUHANDLER(local_history)
+MULTIHANDLER(localhistory)
{
- return nsgtk_window_history_button_clicked(GTK_WIDGET(widget), g);
+ struct browser_window *bw =
+ gui_window_get_browser_window(g->top_level);
+
+ int x,y, width, height, mainwidth, mainheight, margin = 20;
+ /* if entries of the same url but different frag_ids have been added
+ * the history needs redrawing (what throbber code normally does)
+ */
+ history_size(bw->history, &width, &height);
+ nsgtk_window_update_back_forward(g);
+ gtk_window_get_position(g->window, &x, &y);
+ gtk_window_get_size(g->window, &mainwidth, &mainheight);
+ width = (width + g->historybase + margin > mainwidth) ?
+ mainwidth - g->historybase : width + margin;
+ height = (height + g->toolbarbase + margin > mainheight) ?
+ mainheight - g->toolbarbase : height + margin;
+ gtk_window_set_default_size(g->history_window->window, width, height);
+ gtk_widget_set_size_request(GTK_WIDGET(g->history_window->window),
+ -1, -1);
+ gtk_window_resize(g->history_window->window, width, height);
+ gtk_window_set_transient_for(g->history_window->window, g->window);
+ gtk_window_set_opacity(g->history_window->window, 0.9);
+ gtk_widget_show(GTK_WIDGET(g->history_window->window));
+ gtk_window_move(g->history_window->window, x + g->historybase, y +
+ g->toolbarbase);
+ gdk_window_raise(GTK_WIDGET(g->history_window->window)->window);
+
+ return TRUE;
}
-MENUHANDLER(global_history)
+MULTIHANDLER(globalhistory)
{
gtk_widget_show(GTK_WIDGET(wndHistory));
gdk_window_raise(GTK_WIDGET(wndHistory)->window);
@@ -1127,49 +1313,89 @@ MENUHANDLER(global_history)
return TRUE;
}
-MENUHANDLER(next_tab)
+MULTIHANDLER(addbookmarks)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
+ return TRUE;
+}
- gtk_notebook_next_page(gw->notebook);
-
+MULTIHANDLER(showbookmarks)
+{
return TRUE;
}
-MENUHANDLER(prev_tab)
+MULTIHANDLER(openlocation)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
+ gtk_widget_grab_focus(GTK_WIDGET(g->url_bar));
+ return TRUE;
+}
- gtk_notebook_prev_page(gw->notebook);
+MULTIHANDLER(nexttab)
+{
+ gtk_notebook_next_page(g->notebook);
return TRUE;
}
-MENUHANDLER(close_tab)
+MULTIHANDLER(prevtab)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
+ gtk_notebook_prev_page(g->notebook);
- nsgtk_tab_close_current(gw->notebook);
+ return TRUE;
+}
+
+MULTIHANDLER(closetab)
+{
+ nsgtk_tab_close_current(g->notebook);
return TRUE;
}
-MENUHANDLER(about)
+MULTIHANDLER(contents)
{
- struct gtk_scaffolding *gw = (struct gtk_scaffolding *)g;
- nsgtk_about_dialog_init(gw->window,
- nsgtk_get_browser_for_gui(gw->top_level),
+ return TRUE;
+}
+
+MULTIHANDLER(guide)
+{
+ return TRUE;
+}
+
+MULTIHANDLER(info)
+{
+ return TRUE;
+}
+
+MULTIHANDLER(about)
+{
+ nsgtk_about_dialog_init(g->window,
+ gui_window_get_browser_window(g->top_level),
netsurf_version);
return TRUE;
}
+BUTTONHANDLER(history)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ return nsgtk_on_localhistory_activate(g);
+}
+
+gboolean nsgtk_filter_directory(const GtkFileFilterInfo *info,
+ gpointer data)
+{
+ DIR *d = opendir(info->filename);
+ if (d == NULL)
+ return FALSE;
+ closedir(d);
+ return TRUE;
+}
+
/* signal handler functions for the local history window */
gboolean nsgtk_history_expose_event(GtkWidget *widget,
GdkEventExpose *event, gpointer g)
{
struct gtk_history_window *hw = (struct gtk_history_window *)g;
struct browser_window *bw =
- nsgtk_get_browser_for_gui(hw->g->top_level);
+ gui_window_get_browser_window(hw->g->top_level);
current_widget = widget;
current_drawable = widget->window;
@@ -1190,12 +1416,16 @@ gboolean nsgtk_history_expose_event(GtkWidget *widget,
return FALSE;
}
+#undef MULTIHANDLER
+#undef CHECKHANDLER
+#undef BUTTONHANDLER
+
gboolean nsgtk_history_button_press_event(GtkWidget *widget,
GdkEventButton *event, gpointer g)
{
struct gtk_history_window *hw = (struct gtk_history_window *)g;
struct browser_window *bw =
- nsgtk_get_browser_for_gui(hw->g->top_level);
+ gui_window_get_browser_window(hw->g->top_level);
LOG(("X=%g, Y=%g", event->x, event->y));
@@ -1209,8 +1439,10 @@ gboolean nsgtk_history_button_press_event(GtkWidget *widget,
nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
{
- struct gtk_scaffolding *g = malloc(sizeof(*g));
-
+ struct gtk_scaffolding *g = malloc(sizeof(*g));
+ char *searchname;
+ int i;
+
LOG(("Constructing a scaffold of %p for gui_window %p", g, toplevel));
g->top_level = toplevel;
@@ -1220,29 +1452,78 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
/* load the window template from the glade xml file, and extract
* widget references from it for later use.
*/
- g->xml = glade_xml_new(glade_file_location, "wndBrowser", NULL);
+ g->xml = glade_xml_new(glade_netsurf_file_location,
+ "wndBrowser", NULL);
glade_xml_signal_autoconnect(g->xml);
g->window = GTK_WINDOW(GET_WIDGET("wndBrowser"));
g->notebook = GTK_NOTEBOOK(GET_WIDGET("notebook"));
- g->url_bar = GTK_ENTRY(GET_WIDGET("URLBar"));
g->menu_bar = GTK_MENU_BAR(GET_WIDGET("menubar"));
g->status_bar = GTK_STATUSBAR(GET_WIDGET("statusbar"));
- g->edit_menu = GTK_MENU_ITEM(GET_WIDGET("menuitem_edit"));
- g->tabs_menu = GTK_MENU_ITEM(GET_WIDGET("menuitem_tabs"));
g->tool_bar = GTK_TOOLBAR(GET_WIDGET("toolbar"));
- g->back_button = GTK_TOOL_BUTTON(GET_WIDGET("toolBack"));
- g->forward_button = GTK_TOOL_BUTTON(GET_WIDGET("toolForward"));
- g->stop_button = GTK_TOOL_BUTTON(GET_WIDGET("toolStop"));
- g->reload_button = GTK_TOOL_BUTTON(GET_WIDGET("toolReload"));
- g->back_menu = GTK_MENU_ITEM(GET_WIDGET("back"));
- g->history_button = GTK_TOOL_BUTTON(GET_WIDGET("toolHistory"));
- g->forward_menu = GTK_MENU_ITEM(GET_WIDGET("forward"));
- g->stop_menu = GTK_MENU_ITEM(GET_WIDGET("stop"));
- g->reload_menu = GTK_MENU_ITEM(GET_WIDGET("reload"));
- g->throbber = GTK_IMAGE(GET_WIDGET("throbber"));
+
+ g->search = malloc(sizeof(struct gtk_search));
+ if (g->search == NULL) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ g->search->bar = GTK_TOOLBAR(GET_WIDGET("searchbar"));
+ g->search->entry = GTK_ENTRY(GET_WIDGET("searchEntry"));
+
+ g->search->buttons[0] = GTK_TOOL_BUTTON(GET_WIDGET("searchBackButton"));
+ g->search->buttons[1] = GTK_TOOL_BUTTON(GET_WIDGET(
+ "searchForwardButton"));
+ g->search->buttons[2] = GTK_TOOL_BUTTON(GET_WIDGET(
+ "closeSearchButton"));
+ g->search->checkAll = GTK_CHECK_BUTTON(GET_WIDGET("checkAllSearch"));
+ g->search->caseSens = GTK_CHECK_BUTTON(GET_WIDGET("caseSensButton"));
+
+ GtkAccelGroup *group = gtk_accel_group_new();
+ gtk_window_add_accel_group(g->window, group);
+
+
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ g->buttons[i] = malloc(sizeof(struct nsgtk_button_connect));
+ if (g->buttons[i] == NULL) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ g->buttons[i]->button = NULL;
+ g->buttons[i]->location = -1;
+ g->buttons[i]->sensitivity = true;
+ g->buttons[i]->main = NULL;
+ g->buttons[i]->rclick = NULL;
+ g->buttons[i]->popup = NULL;
+ g->buttons[i]->mhandler = NULL;
+ g->buttons[i]->bhandler = NULL;
+ g->buttons[i]->dataplus = NULL;
+ g->buttons[i]->dataminus = NULL;
+ }
+ /* here custom toolbutton adding code */
+ g->offset = 0;
+ g->toolbarmem = 0;
+ g->toolbarbase = 0;
+ g->historybase = 0;
+ nsgtk_toolbar_customization_load(g);
+ nsgtk_toolbar_set_physical(g);
+#define MAKE_MENUS(q)\
+ g->q##_menu = nsgtk_menu_##q##_menu(group);\
+ g->rclick_##q##_menu = nsgtk_menu_##q##_menu(group);\
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(GET_WIDGET("menuitem_" #q)),\
+ GTK_WIDGET(g->q##_menu->q##_menu));\
+ gtk_menu_set_accel_group(g->q##_menu->q##_menu, group)
+ MAKE_MENUS(file);
+ MAKE_MENUS(edit);
+ MAKE_MENUS(view);
+ MAKE_MENUS(nav);
+ MAKE_MENUS(tabs);
+ MAKE_MENUS(help);
+#undef MAKE_MENUS
+ g->edit_menu_item = GTK_MENU_ITEM(GET_WIDGET("menuitem_edit"));
+ g->tabs_menu_item = GTK_MENU_ITEM(GET_WIDGET("menuitem_tabs"));
g->preferences_dialog = NULL;
-
+
nscss_screen_dpi = FLTTOFIX(gdk_screen_get_resolution(
gtk_widget_get_screen(GTK_WIDGET(g->window))));
LOG(("Set CSS DPI to %f", FIXTOFLT(nscss_screen_dpi)));
@@ -1276,16 +1557,18 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
break;
case GTK_TOOLBAR_BOTH:
case GTK_TOOLBAR_BOTH_HORIZ:
- option_button_type = 3;
- break;
+ /* no labels in default configuration */
default:
/* No system default, so use large icons */
option_button_type = 2;
break;
}
}
-
+
switch (option_button_type) {
+ /* case 0 is 'unset' [from fresh install / clearing options]
+ * see above */
+
case 1: /* Small icons */
gtk_toolbar_set_style(GTK_TOOLBAR(g->tool_bar),
GTK_TOOLBAR_ICONS);
@@ -1311,26 +1594,19 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
break;
}
+ gtk_toolbar_set_show_arrow(g->tool_bar, TRUE);
+ gtk_widget_show_all(GTK_WIDGET(g->tool_bar));
nsgtk_tab_init(GTK_WIDGET(g->notebook));
- /* set the URL entry box to expand, as we can't do this from within
- * glade because of the way it emulates toolbars.
- */
- gtk_tool_item_set_expand(GTK_TOOL_ITEM(GET_WIDGET("toolURLBar")),
- TRUE);
-
- /* disable toolbar buttons that make no sense initially. */
- gtk_widget_set_sensitive(GTK_WIDGET(g->back_button), FALSE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->forward_button), FALSE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->stop_button), FALSE);
-
+ gtk_widget_set_size_request(GTK_WIDGET(
+ g->buttons[HISTORY_BUTTON]->button), 20, -1);
+
/* create the local history window to be associated with this browser */
g->history_window = malloc(sizeof(struct gtk_history_window));
g->history_window->g = g;
g->history_window->window =
GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
gtk_window_set_transient_for(g->history_window->window, g->window);
- gtk_window_set_default_size(g->history_window->window, 400, 400);
gtk_window_set_title(g->history_window->window, "NetSurf History");
gtk_window_set_type_hint(g->history_window->window,
GDK_WINDOW_TYPE_HINT_UTILITY);
@@ -1356,7 +1632,6 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
/* set up URL bar completion */
g->url_bar_completion = gtk_entry_completion_new();
- gtk_entry_set_completion(g->url_bar, g->url_bar_completion);
gtk_entry_completion_set_match_func(g->url_bar_completion,
nsgtk_completion_match, NULL, NULL);
gtk_entry_completion_set_model(g->url_bar_completion,
@@ -1370,8 +1645,8 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
NULL);
/* set up the throbber. */
- gtk_image_set_from_pixbuf(g->throbber, nsgtk_throbber->framedata[0]);
g->throb_frame = 0;
+
#define CONNECT(obj, sig, callback, ptr) \
g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
@@ -1379,8 +1654,8 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
/* connect history window signals to their handlers */
CONNECT(g->history_window->drawing_area, "expose_event",
nsgtk_history_expose_event, g->history_window);
-// CONNECT(g->history_window->drawing_area, "motion_notify_event",
-// nsgtk_history_motion_notify_event, g->history_window);
+ /*CONNECT(g->history_window->drawing_area, "motion_notify_event",
+ nsgtk_history_motion_notify_event, g->history_window);*/
CONNECT(g->history_window->drawing_area, "button_press_event",
nsgtk_history_button_press_event, g->history_window);
CONNECT(g->history_window->window, "delete_event",
@@ -1393,35 +1668,67 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
/* connect signals to handlers. */
CONNECT(g->window, "delete-event", nsgtk_window_delete_event, g);
- CONNECT(g->window, "destroy", nsgtk_window_destroy_event, g);
- /* toolbar, URL bar, and menu bar signal handlers */
- CONNECT(g->edit_menu, "show", nsgtk_window_edit_menu_clicked, g);
- CONNECT(g->edit_menu, "hide", nsgtk_window_edit_menu_hidden, g);
- CONNECT(g->back_button, "clicked", nsgtk_window_back_button_clicked,
+ /* toolbar URL bar menu bar search bar signal handlers */
+ CONNECT(g->edit_menu_item, "show", nsgtk_window_edit_menu_clicked, g);
+ CONNECT(g->edit_menu_item, "hide", nsgtk_window_edit_menu_hidden, g);
+ CONNECT(g->search->buttons[1], "clicked",
+ nsgtk_search_forward_button_clicked, g);
+ CONNECT(g->search->buttons[0], "clicked",
+ nsgtk_search_back_button_clicked, g);
+ CONNECT(g->search->entry, "changed", nsgtk_search_entry_changed, g);
+ CONNECT(g->search->entry, "activate", nsgtk_search_entry_activate, g);
+ CONNECT(g->search->entry, "key-press-event", nsgtk_search_entry_key, g);
+ CONNECT(g->search->buttons[2], "clicked",
+ nsgtk_search_close_button_clicked, g);
+ CONNECT(g->search->caseSens, "toggled", nsgtk_search_entry_changed,
g);
- CONNECT(g->forward_button, "clicked",
- nsgtk_window_forward_button_clicked, g);
- CONNECT(g->history_button, "clicked",
- nsgtk_window_history_button_clicked, g);
- CONNECT(g->stop_button, "clicked", nsgtk_window_stop_button_clicked,
- g);
- CONNECT(g->reload_button, "clicked",
- nsgtk_window_reload_button_clicked, g);
- CONNECT(GET_WIDGET("toolHome"), "clicked",
- nsgtk_window_home_button_clicked, g);
- CONNECT(g->url_bar, "activate", nsgtk_window_url_activate_event, g);
- CONNECT(g->url_bar, "changed", nsgtk_window_url_changed, g);
+
+ CONNECT(g->tool_bar, "popup-context-menu",
+ nsgtk_window_tool_bar_clicked, g);
+ g->popup_xml = glade_xml_new(glade_netsurf_file_location, "menuPopup", NULL);
/* set up the menu signal handlers */
- nsgtk_attach_menu_handlers(g->xml, g);
+ nsgtk_scaffolding_toolbar_init(g);
+ nsgtk_toolbar_connect_all(g);
+ nsgtk_attach_menu_handlers(g);
+
+ /* prepare to set the web search ico */
+
+ /* init web search prefs from file */
+ search_web_provider_details(option_search_provider);
+
+ /* potentially retrieve ico */
+ if (search_web_ico() == NULL)
+ search_web_retrieve_ico(false);
+
+ /* set entry */
+ searchname = search_web_provider_name();
+ if (searchname != NULL) {
+ char searchcontent[strlen(searchname) + SLEN("Search ") + 1];
+ sprintf(searchcontent, "Search %s", searchname);
+ nsgtk_scaffolding_set_websearch(g, searchcontent);
+ free(searchname);
+ }
+#define POPUP_ATTACH(q) gtk_menu_item_set_submenu( \
+ GTK_MENU_ITEM(glade_xml_get_widget(g->popup_xml,\
+ "menupopup_" #q)), GTK_WIDGET(g->rclick_##q##_menu->q##_menu));\
+
+ POPUP_ATTACH(file);
+ POPUP_ATTACH(edit);
+ POPUP_ATTACH(view);
+ POPUP_ATTACH(nav);
+ POPUP_ATTACH(tabs);
+ POPUP_ATTACH(help);
+#undef POPUP_ATTACH
+ nsgtk_scaffolding_initial_sensitivity(g);
+
g->being_destroyed = 0;
g->fullscreen = false;
/* create the popup version of the menu */
- g->popup_xml = glade_xml_new(glade_file_location, "menuPopup", NULL);
g->popup_menu = GTK_MENU(glade_xml_get_widget(g->popup_xml,
"menuPopup"));
@@ -1430,54 +1737,50 @@ nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel)
* gtk_menu_shell_append (GTK_MENU_SHELL(g->popup_menu),
* GTK_WIDGET(glade_xml_get_widget(g->xml, "back"))); */
CONNECT(g->popup_menu, "hide", nsgtk_window_popup_menu_hidden, g);
- CONNECT(glade_xml_get_widget(g->popup_xml, "popupBack"), "activate",
- nsgtk_window_back_button_clicked, g);
- CONNECT(glade_xml_get_widget(g->popup_xml, "popupForward"),"activate",
- nsgtk_window_forward_button_clicked, g);
- CONNECT(glade_xml_get_widget(g->popup_xml, "popupReload"), "activate",
- nsgtk_window_reload_button_clicked, g);
+
CONNECT(glade_xml_get_widget(g->popup_xml, "save_link_popup"),
- "activate", nsgtk_on_save_link_activate, g);
+ "activate", nsgtk_on_savelink_activate, g);
CONNECT(glade_xml_get_widget(g->popup_xml,
- "open_link_in_focused_tab_popup"),
- "activate",
- nsgtk_on_open_link_in_focused_tab_activate, g);
+ "open_link_in_focused_tab_popup"), "activate",
+ nsgtk_on_linkfocused_activate, g);
CONNECT(glade_xml_get_widget(g->popup_xml,
- "open_link_in_background_tab_popup"),
- "activate",
- nsgtk_on_open_link_in_background_tab_activate, g);
+ "open_link_in_background_tab_popup"), "activate",
+ nsgtk_on_linkbackground_activate, g);
CONNECT(glade_xml_get_widget(g->popup_xml, "cut_popup"), "activate",
nsgtk_on_cut_activate, g);
CONNECT(glade_xml_get_widget(g->popup_xml, "copy_popup"), "activate",
nsgtk_on_copy_activate, g);
- CONNECT(glade_xml_get_widget(g->popup_xml, "paste_popup"),"activate",
- nsgtk_on_paste_activate, g);
-
-#define POPUP_ATTACH(x, y) gtk_menu_item_set_submenu( \
- GTK_MENU_ITEM(glade_xml_get_widget(g->popup_xml, x)),\
- GTK_WIDGET(glade_xml_get_widget(g->xml, y)))
-
- POPUP_ATTACH("menupopup_file", "menumain_file");
- POPUP_ATTACH("menupopup_edit", "menumain_edit");
- POPUP_ATTACH("menupopup_view", "menumain_view");
- POPUP_ATTACH("menupopup_navigate", "menumain_navigate");
- POPUP_ATTACH("menupopup_help", "menumain_help");
-
-#undef POPUP_ATTACH
+ CONNECT(glade_xml_get_widget(g->popup_xml, "paste_popup"), "activate",
+ nsgtk_on_paste_activate, g);
+ CONNECT(glade_xml_get_widget(g->popup_xml, "customize_popup"),
+ "activate", nsgtk_on_customize_activate, g);
/* hides redundant popup menu items */
GList *widgets = glade_xml_get_widget_prefix(g->popup_xml,
"menupopup");
for (; widgets != NULL; widgets = widgets->next)
gtk_widget_hide(GTK_WIDGET(widgets->data));
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml, "customize_popup"));
+
+ /* attach to the list */
+ if (scaf_list)
+ scaf_list->prev = g;
+ g->next = scaf_list;
+ g->prev = NULL;
+ scaf_list = g;
+
+ /* call functions that need access from the list */
+ nsgtk_theme_init();
+ nsgtk_theme_implement(g);
- /* disable PDF-requiring menu items */
-#ifndef WITH_PDF_EXPORT
- gtk_widget_set_sensitive(GET_WIDGET("export_pdf"), FALSE);
-#endif
-
+ /* set web search ico */
+ if (search_web_ico() != NULL)
+ gui_window_set_search_ico(search_web_ico());
+
/* finally, show the window. */
gtk_widget_show(GTK_WIDGET(g->window));
+ LOG(("creation complete"));
+
return g;
}
@@ -1516,17 +1819,16 @@ void gui_window_set_url(struct gui_window *_g, const char *url)
{
struct gtk_scaffolding *g = nsgtk_get_scaffold(_g);
if (g->top_level != _g) return;
- gtk_entry_set_text(g->url_bar, url);
- gtk_editable_set_position(GTK_EDITABLE(g->url_bar), -1);
+ gtk_entry_set_text(GTK_ENTRY(g->url_bar), url);
+ gtk_editable_set_position(GTK_EDITABLE(g->url_bar), -1);
}
void gui_window_start_throbber(struct gui_window* _g)
{
struct gtk_scaffolding *g = nsgtk_get_scaffold(_g);
- gtk_widget_set_sensitive(GTK_WIDGET(g->stop_button), TRUE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->reload_button), FALSE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->stop_menu), TRUE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->reload_menu), FALSE);
+ g->buttons[STOP_BUTTON]->sensitivity = true;
+ g->buttons[RELOAD_BUTTON]->sensitivity = false;
+ nsgtk_scaffolding_set_sensitivity(g);
nsgtk_window_update_back_forward(g);
@@ -1536,88 +1838,428 @@ void gui_window_start_throbber(struct gui_window* _g)
void gui_window_stop_throbber(struct gui_window* _g)
{
struct gtk_scaffolding *g = nsgtk_get_scaffold(_g);
- gtk_widget_set_sensitive(GTK_WIDGET(g->stop_button), FALSE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->reload_button), TRUE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->stop_menu), FALSE);
- gtk_widget_set_sensitive(GTK_WIDGET(g->reload_menu), TRUE);
-
+ g->buttons[STOP_BUTTON]->sensitivity = false;
+ g->buttons[RELOAD_BUTTON]->sensitivity = true;
nsgtk_window_update_back_forward(g);
-
schedule_remove(nsgtk_throb, g);
+ if ((g == NULL) || (g->throbber == NULL) || (nsgtk_throbber == NULL) ||
+ (nsgtk_throbber->framedata == NULL) ||
+ (nsgtk_throbber->framedata[0] == NULL))
+ return;
gtk_image_set_from_pixbuf(g->throbber, nsgtk_throbber->framedata[0]);
}
-gboolean nsgtk_scaffolding_is_busy(struct gtk_scaffolding *scaffold)
+/**
+ * set favicon
+ */
+void gui_window_set_icon(struct gui_window *_g, struct content *icon)
+{
+ struct gtk_scaffolding *g = nsgtk_get_scaffold(_g);
+ GtkImage *iconImage = NULL;
+ if (g->icoFav != NULL)
+ g_object_unref(g->icoFav);
+ if ((icon != NULL) && (icon->type == CONTENT_ICO)) {
+ nsico_set_bitmap_from_size(icon, 16, 16);
+ }
+ if ((icon != NULL) && (icon->bitmap != NULL)) {
+ GdkPixbuf *pb = gtk_bitmap_get_primary(icon->bitmap);
+ if ((pb != NULL) && (gdk_pixbuf_get_width(pb) > 0) &&
+ (gdk_pixbuf_get_height(pb) > 0)) {
+ pb = gdk_pixbuf_scale_simple(pb, 16, 16,
+ GDK_INTERP_HYPER);
+ iconImage = GTK_IMAGE(
+ gtk_image_new_from_pixbuf(pb));
+ } else {
+ iconImage = NULL;
+ }
+ }
+ if (iconImage == NULL) {
+ char imagepath[strlen(res_dir_location) + SLEN("html.png")
+ + 1];
+ sprintf(imagepath, "%shtml.png", res_dir_location);
+ iconImage = GTK_IMAGE(gtk_image_new_from_file(imagepath));
+ }
+ g->icoFav = iconImage;
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(g->url_bar),
+ SEXY_ICON_ENTRY_PRIMARY, GTK_IMAGE(g->icoFav));
+ gtk_widget_show_all(GTK_WIDGET(g->buttons[URL_BAR_ITEM]->button));
+}
+
+void gui_window_set_search_ico(struct content *ico)
+{
+ GdkPixbuf *pbico = NULL;
+ GtkImage *searchico = NULL;
+ nsgtk_scaffolding *current;
+ if (ico == NULL)
+ ico = search_web_ico();
+
+ if ((ico != NULL) && (ico->type == CONTENT_ICO)) {
+ nsico_set_bitmap_from_size(ico, 20, 20);
+ }
+ if ((ico != NULL) && (ico->bitmap != NULL)) {
+ pbico = gtk_bitmap_get_primary(ico->bitmap);
+ if ((pbico != NULL) && (gdk_pixbuf_get_width(pbico) > 0) &&
+ (gdk_pixbuf_get_height(pbico) > 0)) {
+ pbico = gdk_pixbuf_scale_simple(pbico, 20, 20,
+ GDK_INTERP_HYPER);
+ current = scaf_list;
+ searchico = GTK_IMAGE(
+ gtk_image_new_from_pixbuf(pbico));
+ } else {
+ searchico = NULL;
+ }
+ }
+ /* add ico to toolbar */
+ current = scaf_list;
+ while (current) {
+ if (searchico != NULL) {
+ current->webSearchIco = searchico;
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(
+ current->webSearchEntry),
+ SEXY_ICON_ENTRY_PRIMARY,
+ current->webSearchIco);
+ }
+ searchico = GTK_IMAGE(gtk_image_new_from_pixbuf(pbico));
+ current = current->next;
+ }
+}
+
+bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g)
{
/* We are considered "busy" if the stop button is sensitive */
- return GTK_WIDGET_SENSITIVE((GTK_WIDGET(scaffold->stop_button)));
+ return g->buttons[STOP_BUTTON]->sensitivity;
+}
+
+GtkWindow* nsgtk_scaffolding_window(nsgtk_scaffolding *g)
+{
+ return g->window;
+}
+
+GtkNotebook* nsgtk_scaffolding_notebook(nsgtk_scaffolding *g)
+{
+ return g->notebook;
+}
+
+GtkWidget *nsgtk_scaffolding_urlbar(nsgtk_scaffolding *g)
+{
+ return g->url_bar;
+}
+
+GtkWidget *nsgtk_scaffolding_websearch(nsgtk_scaffolding *g)
+{
+ return g->webSearchEntry;
+}
+
+
+GtkToolbar *nsgtk_scaffolding_toolbar(nsgtk_scaffolding *g)
+{
+ return g->tool_bar;
+}
+
+struct nsgtk_button_connect *nsgtk_scaffolding_button(nsgtk_scaffolding *g,
+ int i)
+{
+ return g->buttons[i];
+}
+
+struct gtk_search *nsgtk_scaffolding_search(nsgtk_scaffolding *g)
+{
+ return g->search;
+}
+
+GtkMenuBar *nsgtk_scaffolding_menu_bar(nsgtk_scaffolding *g)
+{
+ return g->menu_bar;
}
-GtkWindow* nsgtk_scaffolding_get_window (struct gui_window *g)
+struct gtk_history_window *nsgtk_scaffolding_history_window(nsgtk_scaffolding
+ *g)
{
- return g->scaffold->window;
+ return g->history_window;
}
-GtkNotebook* nsgtk_scaffolding_get_notebook (struct gui_window *g)
+nsgtk_scaffolding *nsgtk_scaffolding_iterate(nsgtk_scaffolding *g)
{
- return g->scaffold->notebook;
+ return g->next;
+}
+
+void nsgtk_scaffolding_reset_offset(nsgtk_scaffolding *g)
+{
+ g->offset = 0;
+}
+
+void nsgtk_scaffolding_update_url_bar_ref(nsgtk_scaffolding *g)
+{
+ g->url_bar = GTK_WIDGET(gtk_bin_get_child(GTK_BIN(
+ nsgtk_scaffolding_button(g, URL_BAR_ITEM)->button)));
+ g->icoFav = sexy_icon_entry_get_icon(SEXY_ICON_ENTRY(g->url_bar),
+ SEXY_ICON_ENTRY_PRIMARY);
+
+ gtk_entry_set_completion(GTK_ENTRY(g->url_bar),
+ g->url_bar_completion);
+}
+void nsgtk_scaffolding_update_throbber_ref(nsgtk_scaffolding *g)
+{
+ g->throbber = GTK_IMAGE(gtk_bin_get_child(GTK_BIN(gtk_bin_get_child(
+ GTK_BIN(g->buttons[THROBBER_ITEM]->button)))));
+}
+
+void nsgtk_scaffolding_update_websearch_ref(nsgtk_scaffolding *g)
+{
+ g->webSearchEntry = gtk_bin_get_child(GTK_BIN(
+ g->buttons[WEBSEARCH_ITEM]->button));
+ g->webSearchIco = sexy_icon_entry_get_icon(SEXY_ICON_ENTRY(
+ g->webSearchEntry), SEXY_ICON_ENTRY_PRIMARY);
+}
+
+void nsgtk_scaffolding_set_websearch(nsgtk_scaffolding *g, const char *content)
+{
+ /* this code appears technically correct, though currently has no
+ * effect at all - tinkering encouraged */
+ PangoLayout *lo = gtk_entry_get_layout(GTK_ENTRY(g->webSearchEntry));
+ if (lo != NULL) {
+ pango_layout_set_font_description(lo, NULL);
+ PangoFontDescription *desc = pango_font_description_new();
+ if (desc != NULL) {
+ pango_font_description_set_style(desc,
+ PANGO_STYLE_ITALIC);
+ pango_font_description_set_family(desc, "Arial");
+ pango_font_description_set_weight(desc,
+ PANGO_WEIGHT_ULTRALIGHT);
+ pango_font_description_set_size(desc,
+ 10 * PANGO_SCALE);
+ pango_layout_set_font_description(lo, desc);
+ }
+
+ PangoAttrList *list = pango_attr_list_new();
+ if (list != NULL) {
+ PangoAttribute *italic = pango_attr_style_new(
+ PANGO_STYLE_ITALIC);
+ if (italic != NULL) {
+ italic->start_index = 0;
+ italic->end_index = strlen(content);
+ }
+ PangoAttribute *grey = pango_attr_foreground_new(
+ 0x7777, 0x7777, 0x7777);
+ if (grey != NULL) {
+ grey->start_index = 0;
+ grey->end_index = strlen(content);
+ }
+ pango_attr_list_insert(list, italic);
+ pango_attr_list_insert(list, grey);
+ pango_layout_set_attributes(lo, list);
+ pango_attr_list_unref(list);
+ }
+ pango_layout_set_text(lo, content, -1);
+ }
+/* an alternative method */
+/* char *parse = malloc(strlen(content) + 1);
+ PangoAttrList *list = pango_layout_get_attributes(lo);
+ char *markup = g_strconcat("<span foreground='#777777'><i>", content,
+ "</i></span>", NULL);
+ pango_parse_markup(markup, -1, 0, &list, &parse, NULL, NULL);
+ gtk_widget_show_all(g->webSearchEntry);
+*/
+ gtk_entry_set_visibility(GTK_ENTRY(g->webSearchEntry), TRUE);
+ gtk_entry_set_text(GTK_ENTRY(g->webSearchEntry), content);
+}
+
+void nsgtk_scaffolding_toggle_search_bar_visibility(nsgtk_scaffolding *g)
+{
+ gboolean vis;
+ struct browser_window *bw =
+ gui_window_get_browser_window(g->top_level);
+ g_object_get(G_OBJECT(g->search->bar), "visible", &vis, NULL);
+ if (vis) {
+ if ((bw != NULL) && (bw->search_context != NULL))
+ search_destroy_context(bw->search_context);
+ nsgtk_search_set_forward_state(true, bw);
+ nsgtk_search_set_back_state(true, bw);
+ gtk_widget_hide(GTK_WIDGET(g->search->bar));
+ } else {
+ gtk_widget_show(GTK_WIDGET(g->search->bar));
+ gtk_widget_grab_focus(GTK_WIDGET(g->search->entry));
+ }
+}
+
+
+struct gui_window *nsgtk_scaffolding_top_level(nsgtk_scaffolding *g)
+{
+ return g->top_level;
}
void nsgtk_scaffolding_set_top_level (struct gui_window *gw)
{
- gw->scaffold->top_level = gw;
+ nsgtk_get_scaffold(gw)->top_level = gw;
+ struct browser_window *bw = gui_window_get_browser_window(gw);
/* Synchronise the history (will also update the URL bar) */
- nsgtk_window_update_back_forward(gw->scaffold);
-
- /* Ensure the window's title bar is updated */
- if (gw->bw != NULL && gw->bw->current_content != NULL) {
- if (gw->bw->current_content->title != NULL) {
+ nsgtk_window_update_back_forward(nsgtk_get_scaffold(gw));
+ /* clear effects of potential searches */
+ if ((bw != NULL) && (bw->search_context != NULL))
+ search_destroy_context(bw->search_context);
+ nsgtk_search_set_forward_state(true, bw);
+ nsgtk_search_set_back_state(true, bw);
+
+ /* Ensure the window's title bar as well as favicon are updated */
+ if (gui_window_get_browser_window(gw) != NULL &&
+ gui_window_get_browser_window(gw)->current_content
+ != NULL) {
+ if (gui_window_get_browser_window(gw)->current_content->title
+ != NULL) {
gui_window_set_title(gw,
- gw->bw->current_content->title);
+ gui_window_get_browser_window(gw)->
+ current_content->title);
} else {
- gui_window_set_title(gw, gw->bw->current_content->url);
+ gui_window_set_title(gw,
+ gui_window_get_browser_window(gw)->
+ current_content->url);
}
+ if (gui_window_get_browser_window(gw)->current_content->type
+ == CONTENT_HTML)
+ gui_window_set_icon(gw,
+ gui_window_get_browser_window(gw)->
+ current_content->data.html.favicon);
}
}
+void nsgtk_scaffolding_set_sensitivity(struct gtk_scaffolding *g)
+{
+#define SENSITIVITY(q)\
+ i = q##_BUTTON;\
+ if (g->buttons[i]->main != NULL)\
+ gtk_widget_set_sensitive(GTK_WIDGET(\
+ g->buttons[i]->main),\
+ g->buttons[i]->sensitivity);\
+ if (g->buttons[i]->rclick != NULL)\
+ gtk_widget_set_sensitive(GTK_WIDGET(\
+ g->buttons[i]->rclick),\
+ g->buttons[i]->sensitivity);\
+ if ((g->buttons[i]->location != -1) && \
+ (g->buttons[i]->button != NULL))\
+ gtk_widget_set_sensitive(GTK_WIDGET(\
+ g->buttons[i]->button),\
+ g->buttons[i]->sensitivity);\
+ if (g->buttons[i]->popup != NULL)\
+ gtk_widget_set_sensitive(GTK_WIDGET(\
+ g->buttons[i]->popup),\
+ g->buttons[i]->sensitivity);
+
+ int i;
+ SENSITIVITY(STOP)
+ SENSITIVITY(RELOAD)
+ SENSITIVITY(CUT)
+ SENSITIVITY(COPY)
+ SENSITIVITY(PASTE)
+ SENSITIVITY(BACK)
+ SENSITIVITY(FORWARD)
+ SENSITIVITY(NEXTTAB)
+ SENSITIVITY(PREVTAB)
+ SENSITIVITY(CLOSETAB)
+#undef SENSITIVITY
+}
+
+void nsgtk_scaffolding_initial_sensitivity(struct gtk_scaffolding *g)
+{
+ for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ if (g->buttons[i]->main != NULL)
+ gtk_widget_set_sensitive(GTK_WIDGET(
+ g->buttons[i]->main),
+ g->buttons[i]->sensitivity);
+ if (g->buttons[i]->rclick != NULL)
+ gtk_widget_set_sensitive(GTK_WIDGET(
+ g->buttons[i]->rclick),
+ g->buttons[i]->sensitivity);
+ if ((g->buttons[i]->location != -1) &&
+ (g->buttons[i]->button != NULL))
+ gtk_widget_set_sensitive(GTK_WIDGET(
+ g->buttons[i]->button),
+ g->buttons[i]->sensitivity);
+ if (g->buttons[i]->popup != NULL)
+ gtk_widget_set_sensitive(GTK_WIDGET(
+ g->buttons[i]->popup),
+ g->buttons[i]->sensitivity);
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(g->view_menu->images_menuitem),
+ FALSE);
+}
+
void nsgtk_scaffolding_popup_menu(struct gtk_scaffolding *g,
gdouble x, gdouble y)
{
guint available_menu_options = 0;
GtkWidget *widget = NULL;
+
available_menu_options |=
nsgtk_scaffolding_update_link_operations_sensitivity(g,
- g->popup_xml, x, y, TRUE);
+ g->popup_xml, x, y, true);
available_menu_options |=
nsgtk_scaffolding_update_edit_actions_sensitivity(g,
- g->popup_xml, TRUE);
+ g->popup_xml, true);
/* Hide the separator as well */
if (!available_menu_options) {
- widget = glade_xml_get_widget(g->popup_xml, "separator1");
+ widget = glade_xml_get_widget(g->popup_xml, "sep2");
gtk_widget_hide(widget);
}
+ /* hide customize */
+ gtk_widget_hide(glade_xml_get_widget(g->popup_xml, "customize_popup"));
+
gtk_menu_popup(g->popup_menu, NULL, NULL, NULL, NULL, 0,
gtk_get_current_event_time());
}
+/**
+ * reallocate width for history button, reallocate buttons right of history;
+ * memorise base of history button / toolbar
+ */
+void nsgtk_scaffolding_toolbar_size_allocate(GtkWidget *widget,
+ GtkAllocation *alloc, gpointer data)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ int i = nsgtk_toolbar_get_id_from_widget(widget, g);
+ if ((g->toolbarmem == alloc->x) ||
+ (g->buttons[i]->location <
+ g->buttons[HISTORY_BUTTON]->location))
+ /* no reallocation after first adjustment, no reallocation for buttons
+ * left of history button */
+ return;
+ if (widget == GTK_WIDGET(g->buttons[HISTORY_BUTTON]->button)) {
+ if (alloc->width == 20)
+ return;
+
+ g->toolbarbase = alloc->y + alloc->height;
+ g->historybase = alloc->x + 20;
+ if (g->offset == 0)
+ g->offset = alloc->width - 20;
+ alloc->width = 20;
+ } else if (g->buttons[i]->location <=
+ g->buttons[URL_BAR_ITEM]->location) {
+ alloc->x -= g->offset;
+ if (i == URL_BAR_ITEM)
+ alloc->width += g->offset;
+ }
+ g->toolbarmem = alloc->x;
+ gtk_widget_size_allocate(widget, alloc);
+}
+
static guint nsgtk_scaffolding_update_link_operations_sensitivity(
struct gtk_scaffolding *g, GladeXML *xml, gdouble x, gdouble y,
gboolean hide)
{
gboolean is_sensitive;
- GtkWidget *widget1, *widget2, *widget3;
+ GtkWidget *widget[3];
+ int i;
- widget1 = glade_xml_get_widget_prefix(xml, "save_link")->data;
- widget2 = glade_xml_get_widget_prefix(xml,
+ widget[0] = glade_xml_get_widget_prefix(xml, "save_link")->data;
+ widget[1] = glade_xml_get_widget_prefix(xml,
"open_link_in_focused_tab")->data;
- widget3 = glade_xml_get_widget_prefix(xml,
+ widget[2] = glade_xml_get_widget_prefix(xml,
"open_link_in_background_tab")->data;
- struct browser_window *bw = nsgtk_get_browser_for_gui(g->top_level);
+ struct browser_window *bw = gui_window_get_browser_window(g->top_level);
current_menu_link_box = NULL;
if (bw->current_content && bw->current_content->type == CONTENT_HTML) {
@@ -1626,107 +2268,228 @@ static guint nsgtk_scaffolding_update_link_operations_sensitivity(
}
is_sensitive = (current_menu_link_box != NULL) ? TRUE : FALSE;
- gtk_widget_set_sensitive(widget1, is_sensitive);
- gtk_widget_set_sensitive(widget2, is_sensitive);
- gtk_widget_set_sensitive(widget3, is_sensitive);
-
- if (hide == TRUE && current_menu_link_box == NULL) {
- gtk_widget_hide(widget1);
- gtk_widget_hide(widget2);
- gtk_widget_hide(widget3);
+ for (i = 0; i < 3; i++) {
+ gtk_widget_set_sensitive(widget[i], is_sensitive);
+
+ if (hide == true && current_menu_link_box == NULL) {
+ gtk_widget_hide(widget[i]);
+ }
}
return is_sensitive;
}
static guint nsgtk_scaffolding_update_edit_actions_sensitivity(
- struct gtk_scaffolding *g, GladeXML *xml, gboolean hide)
+ struct gtk_scaffolding *g, GladeXML *xml, bool hide)
{
GtkWidget *widget = gtk_window_get_focus(g->window);
- gboolean can_copy, can_cut, can_paste;
gboolean has_selection;
- if (GTK_IS_EDITABLE (widget)) {
- has_selection = gtk_editable_get_selection_bounds
- (GTK_EDITABLE (widget), NULL, NULL);
+ if (GTK_IS_EDITABLE(widget)) {
+ has_selection = gtk_editable_get_selection_bounds(
+ GTK_EDITABLE (widget), NULL, NULL);
- can_copy = has_selection;
- can_cut = has_selection;
- can_paste = TRUE;
+ g->buttons[COPY_BUTTON]->sensitivity = has_selection;
+ g->buttons[CUT_BUTTON]->sensitivity = has_selection;
+ g->buttons[PASTE_BUTTON]->sensitivity = true;
} else {
struct browser_window *bw =
- nsgtk_get_browser_for_gui(g->top_level);
+ gui_window_get_browser_window(g->top_level);
has_selection = bw->sel->defined;
- can_copy = has_selection;
- can_cut = (has_selection && bw->caret_callback != 0);
- can_paste = (bw->paste_callback != 0);
+ g->buttons[COPY_BUTTON]->sensitivity = has_selection;
+ g->buttons[CUT_BUTTON]->sensitivity = (has_selection &&
+ bw->caret_callback != 0);
+ g->buttons[PASTE_BUTTON]->sensitivity =
+ (bw->paste_callback != 0);
}
widget = glade_xml_get_widget_prefix(xml, "copy")->data;
- gtk_widget_set_sensitive (widget, can_copy);
- if (hide && !can_copy)
+ if (hide && !(g->buttons[COPY_BUTTON]->sensitivity))
gtk_widget_hide(widget);
widget = glade_xml_get_widget_prefix(xml, "cut")->data;
- gtk_widget_set_sensitive (widget, can_cut);
- if (hide && !can_cut)
+ if (hide && !(g->buttons[CUT_BUTTON]->sensitivity))
gtk_widget_hide(widget);
widget = glade_xml_get_widget_prefix(xml, "paste")->data;
- gtk_widget_set_sensitive (widget, can_paste);
- if (hide && !can_paste)
+ if (hide && !(g->buttons[PASTE_BUTTON]->sensitivity))
gtk_widget_hide(widget);
-
- return (can_paste | can_cut | can_copy);
+ nsgtk_scaffolding_set_sensitivity(g);
+ return ((g->buttons[COPY_BUTTON]->sensitivity) |
+ (g->buttons[CUT_BUTTON]->sensitivity) |
+ (g->buttons[PASTE_BUTTON]->sensitivity));
}
static void nsgtk_scaffolding_enable_link_operations_sensitivity(
struct gtk_scaffolding *g, GladeXML *xml)
{
- GtkWidget *widget1;
- GtkWidget *widget2;
- GtkWidget *widget3;
+ int i;
+ GtkWidget *widget[3];
- widget1 = glade_xml_get_widget_prefix(xml, "save_link")->data;
- widget2 = glade_xml_get_widget_prefix(xml,
+ widget[0] = glade_xml_get_widget_prefix(xml, "save_link")->data;
+ widget[1] = glade_xml_get_widget_prefix(xml,
"open_link_in_focused_tab")->data;
- widget3 = glade_xml_get_widget_prefix(xml,
+ widget[2] = glade_xml_get_widget_prefix(xml,
"open_link_in_background_tab")->data;
- gtk_widget_set_sensitive(widget1, TRUE);
- gtk_widget_show(widget1);
- gtk_widget_set_sensitive(widget2, TRUE);
- gtk_widget_show(widget2);
- gtk_widget_set_sensitive(widget3, TRUE);
- gtk_widget_show(widget3);
-
-
+ for (i = 0; i < 3; i++) {
+ gtk_widget_set_sensitive(widget[i], TRUE);
+ gtk_widget_show(widget[i]);
+ }
}
static void nsgtk_scaffolding_enable_edit_actions_sensitivity(
struct gtk_scaffolding *g, GladeXML *xml)
{
- GtkWidget *widget1;
- GtkWidget *widget2;
- GtkWidget *widget3;
- GtkWidget *widget4;
- GtkWidget *widget5;
-
- widget1 = glade_xml_get_widget(xml, "separator");
- widget2 = glade_xml_get_widget(xml, "separator1");
- widget3 = glade_xml_get_widget_prefix(xml, "copy")->data;
- widget4 = glade_xml_get_widget_prefix(xml, "cut")->data;
- widget5 = glade_xml_get_widget_prefix(xml, "paste")->data;
-
- gtk_widget_set_sensitive(widget3, TRUE);
- gtk_widget_set_sensitive(widget4, TRUE);
- gtk_widget_set_sensitive(widget5, TRUE);
-
- gtk_widget_show(widget1);
- gtk_widget_show(widget2);
- gtk_widget_show(widget3);
- gtk_widget_show(widget4);
- gtk_widget_show(widget5);
+ int i;
+ GtkWidget *widget[5];
+
+ widget[0] = glade_xml_get_widget(xml, "sep");
+ widget[1] = glade_xml_get_widget(xml, "sep2");
+ widget[2] = glade_xml_get_widget_prefix(xml, "copy")->data;
+ widget[3] = glade_xml_get_widget_prefix(xml, "cut")->data;
+ widget[4] = glade_xml_get_widget_prefix(xml, "paste")->data;
+ g->buttons[PASTE_BUTTON]->sensitivity = true;
+ g->buttons[COPY_BUTTON]->sensitivity = true;
+ g->buttons[CUT_BUTTON]->sensitivity = true;
+ nsgtk_scaffolding_set_sensitivity(g);
+
+ for (i = 0; i < 5; i++)
+ gtk_widget_show(widget[i]);
+
+}
+
+/**
+ * init the array g->buttons[]
+ */
+void nsgtk_scaffolding_toolbar_init(struct gtk_scaffolding *g)
+{
+#define ITEM_MAIN(p, q, r)\
+ g->buttons[p##_BUTTON]->main =\
+ g->q##_menu->r##_menuitem;\
+ g->buttons[p##_BUTTON]->rclick =\
+ g->rclick_##q##_menu->r##_menuitem;\
+ g->buttons[p##_BUTTON]->mhandler =\
+ nsgtk_on_##r##_activate_menu;\
+ g->buttons[p##_BUTTON]->bhandler =\
+ nsgtk_on_##r##_activate_button;\
+ g->buttons[p##_BUTTON]->dataplus =\
+ nsgtk_toolbar_##r##_button_data;\
+ g->buttons[p##_BUTTON]->dataminus =\
+ nsgtk_toolbar_##r##_toolbar_button_data
+#define ITEM_SUB(p, q, r, s)\
+ g->buttons[p##_BUTTON]->main =\
+ g->q##_menu->\
+ r##_submenu->s##_menuitem;\
+ g->buttons[p##_BUTTON]->rclick =\
+ g->rclick_##q##_menu->\
+ r##_submenu->s##_menuitem;\
+ g->buttons[p##_BUTTON]->mhandler =\
+ nsgtk_on_##s##_activate_menu;\
+ g->buttons[p##_BUTTON]->bhandler =\
+ nsgtk_on_##s##_activate_button;\
+ g->buttons[p##_BUTTON]->dataplus =\
+ nsgtk_toolbar_##s##_button_data;\
+ g->buttons[p##_BUTTON]->dataminus =\
+ nsgtk_toolbar_##s##_toolbar_button_data
+#define ITEM_BUTTON(p, q)\
+ g->buttons[p##_BUTTON]->bhandler =\
+ nsgtk_on_##q##_activate;\
+ g->buttons[p##_BUTTON]->dataplus =\
+ nsgtk_toolbar_##q##_button_data;\
+ g->buttons[p##_BUTTON]->dataminus =\
+ nsgtk_toolbar_##q##_toolbar_button_data
+#define ITEM_POP(p, q)\
+ g->buttons[p##_BUTTON]->popup = GTK_IMAGE_MENU_ITEM(\
+ glade_xml_get_widget(g->popup_xml, #q "_popup"))
+#define SENSITIVITY(q)\
+ g->buttons[q##_BUTTON]->sensitivity = false
+#define ITEM_ITEM(p, q)\
+ g->buttons[p##_ITEM]->dataplus =\
+ nsgtk_toolbar_##q##_button_data;\
+ g->buttons[p##_ITEM]->dataminus =\
+ nsgtk_toolbar_##q##_toolbar_button_data
+ ITEM_ITEM(WEBSEARCH, websearch);
+ ITEM_ITEM(THROBBER, throbber);
+ ITEM_MAIN(NEWWINDOW, file, newwindow);
+ ITEM_MAIN(NEWTAB, file, newtab);
+ ITEM_MAIN(OPENFILE, file, openfile);
+ ITEM_MAIN(PRINT, file, print);
+ ITEM_MAIN(CLOSEWINDOW, file, closewindow);
+ ITEM_MAIN(SAVEPAGE, file, savepage);
+ ITEM_MAIN(PRINTPREVIEW, file, printpreview);
+ ITEM_MAIN(PRINT, file, print);
+ ITEM_MAIN(QUIT, file, quit);
+ ITEM_MAIN(CUT, edit, cut);
+ ITEM_MAIN(COPY, edit, copy);
+ ITEM_MAIN(PASTE, edit, paste);
+ ITEM_MAIN(DELETE, edit, delete);
+ ITEM_MAIN(SELECTALL, edit, selectall);
+ ITEM_MAIN(FIND, edit, find);
+ ITEM_MAIN(PREFERENCES, edit, preferences);
+ ITEM_MAIN(STOP, view, stop);
+ ITEM_POP(STOP, stop);
+ ITEM_MAIN(RELOAD, view, reload);
+ ITEM_POP(RELOAD, reload);
+ ITEM_MAIN(FULLSCREEN, view, fullscreen);
+ ITEM_MAIN(VIEWSOURCE, view, viewsource);
+ ITEM_MAIN(DOWNLOADS, view, downloads);
+ ITEM_MAIN(SAVEWINDOWSIZE, view, savewindowsize);
+ ITEM_MAIN(BACK, nav, back);
+ ITEM_POP(BACK, back);
+ ITEM_MAIN(FORWARD, nav, forward);
+ ITEM_POP(FORWARD, forward);
+ ITEM_MAIN(HOME, nav, home);
+ ITEM_MAIN(LOCALHISTORY, nav, localhistory);
+ ITEM_MAIN(GLOBALHISTORY, nav, globalhistory);
+ ITEM_MAIN(ADDBOOKMARKS, nav, addbookmarks);
+ ITEM_MAIN(SHOWBOOKMARKS, nav, showbookmarks);
+ ITEM_MAIN(OPENLOCATION, nav, openlocation);
+ ITEM_MAIN(NEXTTAB, tabs, nexttab);
+ ITEM_MAIN(PREVTAB, tabs, prevtab);
+ ITEM_MAIN(CLOSETAB, tabs, closetab);
+ ITEM_MAIN(CONTENTS, help, contents);
+ ITEM_MAIN(INFO, help, info);
+ ITEM_MAIN(GUIDE, help, guide);
+ ITEM_MAIN(ABOUT, help, about);
+ ITEM_SUB(PLAINTEXT, file, export, plaintext);
+ ITEM_SUB(PDF, file, export, pdf);
+ ITEM_SUB(DRAWFILE, file, export, drawfile);
+ ITEM_SUB(POSTSCRIPT, file, export, postscript);
+ ITEM_SUB(ZOOMPLUS, view, scaleview, zoomplus);
+ ITEM_SUB(ZOOMMINUS, view, scaleview, zoomminus);
+ ITEM_SUB(ZOOMNORMAL, view, scaleview, zoomnormal);
+ ITEM_SUB(TOGGLEDEBUGGING, view, debugging, toggledebugging);
+ ITEM_SUB(SAVEBOXTREE, view, debugging, saveboxtree);
+ ITEM_SUB(SAVEDOMTREE, view, debugging, savedomtree);
+ ITEM_BUTTON(HISTORY, history);
+ /* disable items that make no sense initially, as well as
+ * as-yet-unimplemented items */
+ SENSITIVITY(BACK);
+ SENSITIVITY(FORWARD);
+ SENSITIVITY(STOP);
+ SENSITIVITY(PRINTPREVIEW);
+ SENSITIVITY(DELETE);
+ SENSITIVITY(CONTENTS);
+ SENSITIVITY(DRAWFILE);
+ SENSITIVITY(POSTSCRIPT);
+ SENSITIVITY(ADDBOOKMARKS);
+ SENSITIVITY(SHOWBOOKMARKS);
+ SENSITIVITY(NEXTTAB);
+ SENSITIVITY(PREVTAB);
+ SENSITIVITY(CLOSETAB);
+ SENSITIVITY(GUIDE);
+ SENSITIVITY(INFO);
+#ifndef WITH_PDF_EXPORT
+ SENSITIVITY(PDF);
+#endif
+
+#undef ITEM_MAIN
+#undef ITEM_SUB
+#undef ITEM_BUTTON
+#undef ITEM_POP
+#undef SENSITIVITY
+
}
diff --git a/gtk/gtk_scaffolding.h b/gtk/gtk_scaffolding.h
index f4b6bffd5..07886690b 100644
--- a/gtk/gtk_scaffolding.h
+++ b/gtk/gtk_scaffolding.h
@@ -21,63 +21,219 @@
#include <gtk/gtk.h>
#include <glade/glade.h>
+#include <glib.h>
#include "desktop/gui.h"
#include "desktop/plotters.h"
+#include "gtk/gtk_menu.h"
+#include "gtk/sexy_icon_entry.h"
typedef struct gtk_scaffolding nsgtk_scaffolding;
-struct gtk_scaffolding {
+typedef enum {
+ BACK_BUTTON = 0,
+ HISTORY_BUTTON,
+ FORWARD_BUTTON,
+ STOP_BUTTON,
+ RELOAD_BUTTON,
+ HOME_BUTTON,
+ URL_BAR_ITEM,
+ WEBSEARCH_ITEM,
+ THROBBER_ITEM,
+ NEWWINDOW_BUTTON,
+ NEWTAB_BUTTON,
+ OPENFILE_BUTTON,
+ CLOSETAB_BUTTON,
+ CLOSEWINDOW_BUTTON,
+ SAVEPAGE_BUTTON,
+ PDF_BUTTON,
+ PLAINTEXT_BUTTON,
+ DRAWFILE_BUTTON,
+ POSTSCRIPT_BUTTON,
+ PRINTPREVIEW_BUTTON,
+ PRINT_BUTTON,
+ QUIT_BUTTON,
+ CUT_BUTTON,
+ COPY_BUTTON,
+ PASTE_BUTTON,
+ DELETE_BUTTON,
+ SELECTALL_BUTTON,
+ FIND_BUTTON,
+ PREFERENCES_BUTTON,
+ ZOOMPLUS_BUTTON,
+ ZOOMMINUS_BUTTON,
+ ZOOMNORMAL_BUTTON,
+ FULLSCREEN_BUTTON,
+ VIEWSOURCE_BUTTON,
+ DOWNLOADS_BUTTON,
+ SAVEWINDOWSIZE_BUTTON,
+ TOGGLEDEBUGGING_BUTTON,
+ SAVEBOXTREE_BUTTON,
+ SAVEDOMTREE_BUTTON,
+ LOCALHISTORY_BUTTON,
+ GLOBALHISTORY_BUTTON,
+ ADDBOOKMARKS_BUTTON,
+ SHOWBOOKMARKS_BUTTON,
+ OPENLOCATION_BUTTON,
+ NEXTTAB_BUTTON,
+ PREVTAB_BUTTON,
+ CONTENTS_BUTTON,
+ GUIDE_BUTTON,
+ INFO_BUTTON,
+ ABOUT_BUTTON,
+ PLACEHOLDER_BUTTON /* size indicator; array maximum indices */
+} nsgtk_toolbar_button; /* PLACEHOLDER_BUTTON - 1 */
+
+struct gtk_history_window {
+ struct gtk_scaffolding *g;
GtkWindow *window;
- GtkNotebook *notebook;
- GtkEntry *url_bar;
- GtkEntryCompletion *url_bar_completion;
- GtkStatusbar *status_bar;
- GtkMenuItem *edit_menu;
- GtkMenuItem *tabs_menu;
- GtkToolbar *tool_bar;
- GtkToolButton *back_button;
- GtkToolButton *history_button;
- GtkToolButton *forward_button;
- GtkToolButton *stop_button;
- GtkToolButton *reload_button;
- GtkMenuBar *menu_bar;
- GtkMenuItem *back_menu;
- GtkMenuItem *forward_menu;
- GtkMenuItem *stop_menu;
- GtkMenuItem *reload_menu;
- GtkImage *throbber;
- GtkPaned *status_pane;
-
- GladeXML *xml;
-
- GladeXML *popup_xml;
- GtkMenu *popup_menu;
-
- struct gtk_history_window *history_window;
- GtkDialog *preferences_dialog;
-
- int throb_frame;
- struct gui_window *top_level;
- int being_destroyed;
-
- bool fullscreen;
+ GtkScrolledWindow *scrolled;
+ GtkDrawingArea *drawing_area;
};
-GtkWindow *nsgtk_get_window_for_scaffold(struct gtk_scaffolding *g);
-
-nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel);
-
-gboolean nsgtk_scaffolding_is_busy(nsgtk_scaffolding *scaffold);
-
-GtkWindow* nsgtk_scaffolding_get_window (struct gui_window *g);
+struct gtk_search {
+ GtkToolbar *bar;
+ GtkEntry *entry;
+ GtkToolButton *buttons[3]; /* back, forward, */
+ GtkCheckButton *checkAll; /* close */
+ GtkCheckButton *caseSens;
+};
-GtkNotebook* nsgtk_scaffolding_get_notebook (struct gui_window *g);
+struct nsgtk_button_connect {
+ GtkToolItem *button;
+ int location; /* in toolbar */
+ bool sensitivity;
+ GtkImageMenuItem *main;
+ GtkImageMenuItem *rclick;
+ GtkImageMenuItem *popup;
+ void *mhandler; /* menu item clicked */
+ void *bhandler; /* button clicked */
+ void *dataplus; /* customization -> toolbar */
+ void *dataminus; /* customization -> store */
+};
-void nsgtk_scaffolding_set_top_level (struct gui_window *gw);
+extern nsgtk_scaffolding *scaf_list;
-void nsgtk_scaffolding_destroy(nsgtk_scaffolding *scaffold);
+nsgtk_scaffolding *nsgtk_new_scaffolding(struct gui_window *toplevel);
+bool nsgtk_scaffolding_is_busy(nsgtk_scaffolding *g);
+
+GtkWindow *nsgtk_scaffolding_window(nsgtk_scaffolding *g);
+GtkNotebook *nsgtk_scaffolding_notebook(nsgtk_scaffolding *g);
+GtkWidget *nsgtk_scaffolding_urlbar(nsgtk_scaffolding *g);
+GtkWidget *nsgtk_scaffolding_websearch(nsgtk_scaffolding *g);
+GtkToolbar *nsgtk_scaffolding_toolbar(nsgtk_scaffolding *g);
+struct nsgtk_button_connect *nsgtk_scaffolding_button(nsgtk_scaffolding *g,
+ int i);
+struct gtk_search *nsgtk_scaffolding_search(nsgtk_scaffolding *g);
+GtkMenuBar *nsgtk_scaffolding_menu_bar(nsgtk_scaffolding *g);
+struct gtk_history_window *nsgtk_scaffolding_history_window(nsgtk_scaffolding
+ *g);
+struct gui_window *nsgtk_scaffolding_top_level(nsgtk_scaffolding *g);
+void nsgtk_scaffolding_reset_offset(nsgtk_scaffolding *g);
+nsgtk_scaffolding *nsgtk_scaffolding_iterate(nsgtk_scaffolding *g);
+void nsgtk_scaffolding_toolbar_init(struct gtk_scaffolding *g);
+void nsgtk_scaffolding_update_url_bar_ref(nsgtk_scaffolding *g);
+void nsgtk_scaffolding_update_throbber_ref(nsgtk_scaffolding *g);
+void nsgtk_scaffolding_update_websearch_ref(nsgtk_scaffolding *g);
+void nsgtk_scaffolding_set_websearch(nsgtk_scaffolding *g, const char
+ *content);
+void nsgtk_scaffolding_toggle_search_bar_visibility(nsgtk_scaffolding *g);
+void nsgtk_scaffolding_set_top_level(struct gui_window *g);
+
+void nsgtk_scaffolding_destroy(nsgtk_scaffolding *g);
+
+void nsgtk_scaffolding_set_sensitivity(struct gtk_scaffolding *g);
+void nsgtk_scaffolding_initial_sensitivity(struct gtk_scaffolding *g);
void nsgtk_scaffolding_popup_menu(struct gtk_scaffolding *g, gdouble x,
gdouble y);
+void nsgtk_scaffolding_toolbar_size_allocate(GtkWidget *widget,
+ GtkAllocation *alloc, gpointer data);
+
+gboolean nsgtk_window_url_activate_event(GtkWidget *, gpointer);
+gboolean nsgtk_window_url_changed(GtkWidget *, GdkEventKey *, gpointer);
+
+#define MULTIPROTO(q)\
+gboolean nsgtk_on_##q##_activate(struct gtk_scaffolding *);\
+gboolean nsgtk_on_##q##_activate_menu(GtkMenuItem *, gpointer);\
+gboolean nsgtk_on_##q##_activate_button(GtkButton *, gpointer)
+#define MENUPROTO(q)\
+gboolean nsgtk_on_##q##_activate(GtkMenuItem *, gpointer)
+#define BUTTONPROTO(q)\
+gboolean nsgtk_on_##q##_activate(GtkButton *, gpointer)
+/* prototypes for handlers */
+/* file menu */
+MULTIPROTO(newwindow);
+MULTIPROTO(newtab);
+MULTIPROTO(open_location);
+MULTIPROTO(openfile);
+MULTIPROTO(savepage);
+MULTIPROTO(pdf);
+MULTIPROTO(plaintext);
+MULTIPROTO(drawfile);
+MULTIPROTO(postscript);
+MULTIPROTO(printpreview);
+MULTIPROTO(print);
+MULTIPROTO(closewindow);
+MULTIPROTO(quit);
+
+/* edit menu */
+MULTIPROTO(cut);
+MULTIPROTO(copy);
+MULTIPROTO(paste);
+MULTIPROTO(delete);
+MULTIPROTO(selectall);
+MULTIPROTO(find);
+MULTIPROTO(preferences);
+
+/* view menu */
+MULTIPROTO(stop);
+MULTIPROTO(reload);
+MULTIPROTO(zoomplus);
+MULTIPROTO(zoomnormal);
+MULTIPROTO(zoomminus);
+MULTIPROTO(fullscreen);
+MULTIPROTO(viewsource);
+MENUPROTO(menubar);
+MENUPROTO(toolbar);
+MENUPROTO(statusbar);
+MULTIPROTO(downloads);
+MULTIPROTO(savewindowsize);
+MULTIPROTO(toggledebugging);
+MULTIPROTO(saveboxtree);
+MULTIPROTO(savedomtree);
+
+/* navigate menu */
+MULTIPROTO(back);
+MULTIPROTO(forward);
+MULTIPROTO(home);
+MULTIPROTO(localhistory);
+MULTIPROTO(globalhistory);
+MULTIPROTO(addbookmarks);
+MULTIPROTO(showbookmarks);
+MULTIPROTO(openlocation);
+
+/* tabs menu */
+MULTIPROTO(nexttab);
+MULTIPROTO(prevtab);
+MULTIPROTO(closetab);
+
+/* help menu */
+MULTIPROTO(contents);
+MULTIPROTO(guide);
+MULTIPROTO(info);
+MULTIPROTO(about);
+
+/* popup menu */
+MENUPROTO(customize);
+MENUPROTO(savelink);
+MENUPROTO(linkfocused);
+MENUPROTO(linkbackground);
+
+/* non-menu */
+BUTTONPROTO(history);
+
+#undef MULTIPROTO
+#undef MENUPROTO
+#undef BUTTONPROTO
#endif /* NETSURF_GTK_SCAFFOLDING_H */
diff --git a/gtk/gtk_search.c b/gtk/gtk_search.c
new file mode 100644
index 000000000..bb5d0138c
--- /dev/null
+++ b/gtk/gtk_search.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+ /** \file
+ * Free text search (front component)
+ */
+#include <ctype.h>
+#include <string.h>
+#include <gdk/gdkkeysyms.h>
+#include "gtk/gtk_search.h"
+#include "gtk/gtk_scaffolding.h"
+#include "gtk/gtk_window.h"
+#include "utils/config.h"
+#include "content/content.h"
+#include "desktop/browser.h"
+#include "desktop/gui.h"
+#include "desktop/search.h"
+#include "desktop/searchweb.h"
+#include "desktop/selection.h"
+#include "render/box.h"
+#include "render/html.h"
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+
+static void nsgtk_search_init(struct gtk_scaffolding *g);
+static void nsgtk_search_set_status(bool found, void *p);
+static void nsgtk_search_set_hourglass(bool active, void *p);
+static void nsgtk_search_add_recent(const char *string, void *p);
+
+static struct search_callbacks nsgtk_search_callbacks = {
+ nsgtk_search_set_forward_state,
+ nsgtk_search_set_back_state,
+ nsgtk_search_set_status,
+ nsgtk_search_set_hourglass,
+ nsgtk_search_add_recent
+};
+
+/** connected to the search forward button */
+
+gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ struct browser_window *bw = gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(g));
+ nsgtk_search_init(g);
+ search_flags_t flags = SEARCH_FLAG_FORWARDS |
+ (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ nsgtk_scaffolding_search(g)->caseSens)) ?
+ SEARCH_FLAG_CASE_SENSITIVE : 0) |
+ (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ nsgtk_scaffolding_search(g)->checkAll)) ?
+ SEARCH_FLAG_SHOWALL : 0);
+ if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw))
+ search_step(bw->search_context, flags, gtk_entry_get_text(
+ nsgtk_scaffolding_search(g)->entry));
+ return TRUE;
+}
+
+/** connected to the search back button */
+
+gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ struct browser_window *bw = gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(g));
+ nsgtk_search_init(g);
+ search_flags_t flags = 0 |(gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(
+ nsgtk_scaffolding_search(g)->caseSens)) ?
+ SEARCH_FLAG_CASE_SENSITIVE : 0) |
+ (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ nsgtk_scaffolding_search(g)->checkAll)) ?
+ SEARCH_FLAG_SHOWALL : 0);
+ if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw))
+ search_step(bw->search_context, flags, gtk_entry_get_text(
+ nsgtk_scaffolding_search(g)->entry));
+ return TRUE;
+}
+
+/** preparatory code when the search bar is made visible initially */
+
+void nsgtk_search_init(struct gtk_scaffolding *g)
+{
+ struct content *c;
+
+ assert(gui_window_get_browser_window(nsgtk_scaffolding_top_level(g))
+ != NULL);
+
+ c = gui_window_get_browser_window(nsgtk_scaffolding_top_level(g))->
+ current_content;
+
+ if ((!c) || (c->type != CONTENT_HTML && c->type != CONTENT_TEXTPLAIN))
+ return;
+
+}
+
+/** connected to the search close button */
+
+gboolean nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ nsgtk_scaffolding_toggle_search_bar_visibility(g);
+ return TRUE;
+}
+
+/** connected to the search entry [typing] */
+
+gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ struct browser_window *bw = gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(g));
+ if ((bw != NULL) && (bw->search_context != NULL))
+ search_destroy_context(bw->search_context);
+ nsgtk_search_set_forward_state(true, (void *)bw);
+ nsgtk_search_set_back_state(true, (void *)bw);
+ return TRUE;
+}
+
+/** connected to the search entry [return key] */
+
+gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ struct browser_window *bw = gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(g));
+ nsgtk_search_init(g);
+ search_flags_t flags = SEARCH_FLAG_FORWARDS |
+ (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ nsgtk_scaffolding_search(g)->caseSens)) ?
+ SEARCH_FLAG_CASE_SENSITIVE : 0) |
+ (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
+ nsgtk_scaffolding_search(g)->checkAll)) ?
+ SEARCH_FLAG_SHOWALL : 0);
+ if (search_verify_new(bw, &nsgtk_search_callbacks, (void *)bw))
+ search_step(bw->search_context, flags, gtk_entry_get_text(
+ nsgtk_scaffolding_search(g)->entry));
+ return FALSE;
+}
+
+/** allows escape key to close search bar too */
+
+gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event,
+ gpointer data)
+{
+ if (event->keyval == GDK_Escape) {
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ nsgtk_scaffolding_toggle_search_bar_visibility(g);
+ }
+ return FALSE;
+}
+
+/** connected to the websearch entry [return key] */
+
+gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ temp_open_background = 0;
+ search_web_new_window(gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(g)),
+ (char *)gtk_entry_get_text(GTK_ENTRY(
+ nsgtk_scaffolding_websearch(g))));
+ temp_open_background = -1;
+ return TRUE;
+}
+
+/**
+ * allows a click in the websearch entry field to clear the name of the
+ * provider
+ */
+
+gboolean nsgtk_websearch_clear(GtkWidget *widget, GdkEventFocus *f,
+ gpointer data)
+{
+ struct gtk_scaffolding *g = (struct gtk_scaffolding *)data;
+ gtk_editable_select_region(GTK_EDITABLE(
+ nsgtk_scaffolding_websearch(g)), 0, -1);
+ gtk_widget_grab_focus(GTK_WIDGET(nsgtk_scaffolding_websearch(g)));
+ return TRUE;
+}
+
+/**
+* Change the displayed search status.
+* \param found search pattern matched in text
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void nsgtk_search_set_status(bool found, void *p)
+{
+}
+
+/**
+* display hourglass while searching
+* \param active start/stop indicator
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void nsgtk_search_set_hourglass(bool active, void *p)
+{
+}
+
+/**
+* add search string to recent searches list
+* front is at liberty how to implement the bare notification
+* should normally store a strdup() of the string;
+* core gives no guarantee of the integrity of the const char *
+* \param string search pattern
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void nsgtk_search_add_recent(const char *string, void *p)
+{
+}
+
+/**
+* activate search forwards button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void nsgtk_search_set_forward_state(bool active, void *p)
+{
+ struct browser_window *bw = (struct browser_window *)p;
+ if ((bw != NULL) && (bw->window != NULL)) {
+ struct gtk_scaffolding *g = nsgtk_get_scaffold(bw->window);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search(
+ g)->buttons[1]), active);
+ }
+}
+
+/**
+* activate search back button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
+
+void nsgtk_search_set_back_state(bool active, void *p)
+{
+ struct browser_window *bw = (struct browser_window *)p;
+ if ((bw != NULL) && (bw->window != NULL)) {
+ struct gtk_scaffolding *g = nsgtk_get_scaffold(bw->window);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search(
+ g)->buttons[0]), active);
+ }
+}
diff --git a/gtk/gtk_search.h b/gtk/gtk_search.h
new file mode 100644
index 000000000..981ea5bfd
--- /dev/null
+++ b/gtk/gtk_search.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_GTK_SEARCH_H_
+#define _NETSURF_GTK_SEARCH_H_
+
+#include <gtk/gtk.h>
+#include "gtk/gtk_scaffolding.h"
+
+void nsgtk_search_bar_toggle_visibility(struct gtk_scaffolding * g);
+gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data);
+gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data);
+gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event,
+ gpointer data);
+gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data);
+gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data);
+gboolean nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data);
+gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data);
+gboolean nsgtk_websearch_clear(GtkWidget *widget, GdkEventFocus *f,
+ gpointer data);
+void nsgtk_search_set_forward_state(bool active, void *p);
+void nsgtk_search_set_back_state(bool active, void *p);
+
+#endif
diff --git a/gtk/gtk_selection.c b/gtk/gtk_selection.c
index cf9e1decd..41869d753 100644
--- a/gtk/gtk_selection.c
+++ b/gtk/gtk_selection.c
@@ -79,7 +79,7 @@ void gui_start_selection(struct gui_window *g)
else
g_string_set_size(current_selection, 0);
- gtk_widget_grab_focus(GTK_WIDGET(g->drawing_area));
+ gtk_widget_grab_focus(GTK_WIDGET(nsgtk_window_get_drawing_area(g)));
}
void gui_paste_from_clipboard(struct gui_window *g, int x, int y)
@@ -89,7 +89,8 @@ void gui_paste_from_clipboard(struct gui_window *g, int x, int y)
text = gtk_clipboard_wait_for_text (clipboard);
/* clipboard_wait... converts the string to utf8 for us */
if (text != NULL)
- browser_window_paste_text(g->bw, text, strlen(text), true);
+ browser_window_paste_text(gui_window_get_browser_window(g),
+ text, strlen(text), true);
g_free(text);
}
diff --git a/gtk/gtk_tabs.c b/gtk/gtk_tabs.c
index b54f3cfb9..f0e87bb79 100644
--- a/gtk/gtk_tabs.c
+++ b/gtk/gtk_tabs.c
@@ -23,12 +23,14 @@
#include "desktop/browser.h"
#include "content/content.h"
#include "desktop/options.h"
+#include "desktop/search.h"
#include "utils/utils.h"
#include "gtk/options.h"
+#include "gtk/gtk_search.h"
#include "gtk/gtk_tabs.h"
#define TAB_WIDTH_N_CHARS 15
-#define GET_WIDGET(x) glade_xml_get_widget(gladeWindows, (x))
+#define GET_WIDGET(x) glade_xml_get_widget(gladeNetsurf, (x))
static GtkWidget *nsgtk_tab_label_setup(struct gui_window *window);
static void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child,
@@ -58,15 +60,19 @@ void nsgtk_tab_init(GtkWidget *tabs)
void nsgtk_tab_add(struct gui_window *window, bool background)
{
- GtkWidget *tabs = GTK_WIDGET(nsgtk_scaffolding_get_notebook(window));
+ GtkWidget *tabs = GTK_WIDGET(nsgtk_scaffolding_notebook(
+ nsgtk_get_scaffold(window)));
GtkWidget *tabBox = nsgtk_tab_label_setup(window);
gint remember = gtk_notebook_get_current_page(GTK_NOTEBOOK(tabs));
gtk_notebook_append_page(GTK_NOTEBOOK(tabs),
- GTK_WIDGET(window->scrolledwindow), tabBox);
- /*causes gtk errors can't set a parent
+ GTK_WIDGET(nsgtk_window_get_scrolledwindow(window)),
+ tabBox);
+ /*causes gtk errors can't set a parent */
gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(tabs),
- GTK_WIDGET(window->scrolledwindow), true); */
- gtk_widget_show_all(GTK_WIDGET(window->scrolledwindow));
+ GTK_WIDGET(nsgtk_window_get_scrolledwindow(window)),
+ true);
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_window_get_scrolledwindow(
+ window)));
gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs),
gtk_notebook_get_n_pages(GTK_NOTEBOOK(tabs)) - 1);
if (option_new_blank) {
@@ -75,13 +81,15 @@ void nsgtk_tab_add(struct gui_window *window, bool background)
blankpage = g_strconcat("file:///", res_dir_location,
"blankpage", NULL); */
/* segfaults
- struct browser_window *bw = nsgtk_get_browser_for_gui(window);
+ struct browser_window *bw =
+ gui_window_get_browser_window(window);
browser_window_go(bw, blankpage, 0, true); */
/* free(blankpage); */
}
if (background)
gtk_notebook_set_current_page(GTK_NOTEBOOK(tabs), remember);
- gtk_widget_grab_focus(GTK_WIDGET(window->scaffold->url_bar));
+ gtk_widget_grab_focus(GTK_WIDGET(nsgtk_scaffolding_urlbar(
+ nsgtk_get_scaffold(window))));
}
void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child,
@@ -97,12 +105,14 @@ void nsgtk_tab_visibility_update(GtkNotebook *notebook, GtkWidget *child,
void nsgtk_tab_set_title(struct gui_window *g, const char *title)
{
GtkWidget *label;
- gboolean is_top_level = (g->tab != NULL);
+ GtkWidget *tab;
+ tab = nsgtk_window_get_tab(g);
+ gboolean is_top_level = (tab != NULL);
if (is_top_level) {
- label = g_object_get_data(G_OBJECT(g->tab), "label");
+ label = g_object_get_data(G_OBJECT(tab), "label");
gtk_label_set_text(GTK_LABEL(label), title);
- gtk_widget_set_tooltip_text(g->tab, title);
+ gtk_widget_set_tooltip_text(tab, title);
}
}
@@ -147,7 +157,7 @@ GtkWidget *nsgtk_tab_label_setup(struct gui_window *window)
g_object_set_data(G_OBJECT(hbox), "label", label);
g_object_set_data(G_OBJECT(hbox), "close-button", button);
- window->tab = hbox;
+ nsgtk_window_set_tab(window, hbox);
gtk_widget_show_all(hbox);
return hbox;
@@ -183,6 +193,11 @@ void nsgtk_tab_page_changed(GtkNotebook *notebook, GtkNotebookPage *page,
GtkWidget *window = gtk_notebook_get_nth_page(notebook, page_num);
struct gui_window *gw = g_object_get_data(G_OBJECT(window),
"gui_window");
+ struct browser_window *bw = gui_window_get_browser_window(gw);
+ if ((bw != NULL) && (bw->search_context != NULL))
+ search_destroy_context(bw->search_context);
+ nsgtk_search_set_forward_state(true, bw);
+ nsgtk_search_set_back_state(true, bw);
if (gw)
nsgtk_scaffolding_set_top_level(gw);
}
diff --git a/gtk/gtk_theme.c b/gtk/gtk_theme.c
new file mode 100644
index 000000000..f215cbeea
--- /dev/null
+++ b/gtk/gtk_theme.c
@@ -0,0 +1,773 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include "content/content.h"
+#include "content/content_type.h"
+#include "gtk/gtk_gui.h"
+#include "gtk/gtk_scaffolding.h"
+#include "gtk/gtk_menu.h"
+#include "gtk/gtk_theme.h"
+#include "gtk/gtk_window.h"
+#include "gtk/options.h"
+#include "gtk/dialogs/gtk_options.h"
+#include "utils/container.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+
+enum image_sets {
+ IMAGE_SET_MAIN_MENU = 0,
+ IMAGE_SET_RCLICK_MENU,
+ IMAGE_SET_POPUP_MENU,
+ IMAGE_SET_BUTTONS,
+ IMAGE_SET_COUNT
+};
+
+struct nsgtk_theme_cache {
+ GdkPixbuf *image[PLACEHOLDER_BUTTON];
+ GdkPixbuf *searchimage[SEARCH_BUTTONS_COUNT];
+ /* apng throbber image */
+};
+
+static char *current_theme_name = NULL;
+static struct nsgtk_theme_cache *theme_cache_menu = NULL;
+static struct nsgtk_theme_cache *theme_cache_toolbar = NULL;
+
+static struct nsgtk_theme *nsgtk_theme_default(GtkIconSize s);
+static GtkImage *nsgtk_theme_image_default(nsgtk_toolbar_button i,
+ GtkIconSize s);
+static bool nsgtk_theme_verify(const char *themename);
+static void nsgtk_theme_cache_image(nsgtk_toolbar_button i,
+ const char *filename, const char *path);
+static void nsgtk_theme_cache_searchimage(nsgtk_search_buttons i,
+ const char *filename, const char *path);
+
+#ifdef WITH_THEME_INSTALL
+static struct content *theme_install_content = NULL;
+
+static void theme_install_callback(content_msg msg, struct content *c,
+ intptr_t p1, intptr_t p2, union content_msg_data data);
+static bool theme_install_read(const char *data, unsigned long len);
+#endif
+
+/**
+ * called during gui init phase to retrieve theme name from file then
+ * implement
+ */
+
+void nsgtk_theme_init(void)
+{
+ size_t len;
+ if (option_current_theme == 0)
+ return;
+ len = SLEN("themelist") + strlen(res_dir_location) + 1;
+ char themefile[len];
+ snprintf(themefile, len, "%s%s", res_dir_location, "themelist");
+ nsgtk_scaffolding *list = scaf_list;
+ nsgtk_theme_verify(NULL);
+ FILE *fp = fopen(themefile, "r");
+ if (fp == NULL)
+ return;
+ char buf[50];
+ int row_count = 0;
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ if (buf[0] == '\0')
+ continue;
+
+ if (row_count++ == option_current_theme) {
+ if (current_theme_name != NULL)
+ free(current_theme_name);
+ /* clear the '\n' ["\n\0"->"\0\0"] */
+ buf[strlen(buf) - 1] = '\0';
+ current_theme_name = strdup(buf);
+ break;
+ }
+ }
+ fclose(fp);
+
+ while (list != NULL) {
+ nsgtk_theme_implement(list);
+ list = nsgtk_scaffolding_iterate(list);
+ }
+}
+
+/**
+ * return reference to static global current_theme_name; caller then has
+ * responsibility for global reference
+ */
+
+char *nsgtk_theme_name(void)
+{
+ return current_theme_name;
+}
+
+/**
+ * set static global current_theme_name from param; caller is responsible
+ * for the integrity of the global reference
+ */
+
+void nsgtk_theme_set_name(char *name)
+{
+ current_theme_name = name;
+}
+
+/**
+ * adds a theme name to the list of themes
+ */
+
+void nsgtk_theme_add(const char *themename)
+{
+ size_t len;
+ GtkWidget *notification, *label;
+ len = SLEN("themelist") + strlen(res_dir_location) + 1;
+ char themefile[len];
+ snprintf(themefile, len, "%s%s", res_dir_location, "themelist");
+ /* conduct verification here; no adding duplicates to list */
+ if (nsgtk_theme_verify(themename) == false) {
+ warn_user(messages_get("gtkThemeDup"), 0);
+ return;
+ }
+ FILE *fp = fopen(themefile, "a");
+ if (fp == NULL) {
+ warn_user(messages_get("gtkFileError"), themefile);
+ return;
+ }
+ fprintf(fp, "%s\n", themename);
+ fclose(fp);
+
+ /* notification that theme was added successfully */
+ notification = gtk_dialog_new_with_buttons(messages_get("gtkThemeAdd"),
+ NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK,
+ GTK_RESPONSE_NONE, NULL);
+ if (notification == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ len = SLEN("\t\t\t\t\t\t") + strlen(messages_get("gtkThemeAdd")) + 1;
+ char labelcontent[len];
+ snprintf(labelcontent, len, "\t\t\t%s\t\t\t",
+ messages_get("gtkThemeAdd"));
+ label = gtk_label_new(labelcontent);
+ if (label == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ g_signal_connect_swapped(notification, "response",
+ G_CALLBACK(gtk_widget_destroy), notification);
+ gtk_container_add(GTK_CONTAINER(GTK_DIALOG(notification)->vbox), label);
+ gtk_widget_show_all(notification);
+
+ /* update combo */
+ if (wndPreferences == NULL)
+ return;
+ nsgtk_options_combo_theme_add(themename);
+
+}
+
+/**
+ * \param themename contains a name of theme to check whether it may
+ * properly be added to the list; alternatively NULL to check the integrity
+ * of the list
+ * \return true for themename may be added / every item in the list is
+ * a valid directory
+ */
+
+bool nsgtk_theme_verify(const char *themename)
+{
+ long filelength;
+ FILE *fp;
+ size_t val = SLEN("themelist") + strlen(res_dir_location) + 1;
+ char buf[50];
+ char themefile[val];
+ snprintf(themefile, val, "%s%s", res_dir_location, "themelist");
+ if (themename == NULL) {
+ char *filecontent, *testfile;
+ struct stat sta;
+ fp = fopen(themefile, "r+");
+ if (fp == NULL) {
+ warn_user(messages_get("gtkFileError"), themefile);
+ return true;
+ }
+ fseek(fp, 0L, SEEK_END);
+ filelength = ftell(fp);
+ filecontent = malloc(filelength +
+ SLEN("gtk default theme\n") + SLEN("\n")
+ + 1);
+ if (filecontent == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return true;
+ }
+ strcpy(filecontent, "gtk default theme\n");
+ fseek(fp, 0L, SEEK_SET);
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ /* iterate list */
+ buf[strlen(buf) - 1] = '\0';
+ /* "\n\0" -> "\0\0" */
+ testfile = malloc(strlen(res_dir_location) +
+ SLEN("themes/") + strlen(buf) + 1);
+ if (testfile == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(filecontent);
+ return false;
+ }
+ sprintf(testfile, "%sthemes/%s", res_dir_location,
+ buf);
+ /* check every directory */
+ if (access(testfile, R_OK) == 0) {
+ stat(testfile, &sta);
+ if (S_ISDIR(sta.st_mode)) {
+ buf[strlen(buf)] = '\n';
+ /* "\0\0" -> "\n\0" */
+ strcat(filecontent, buf);
+ }
+ }
+ free(testfile);
+ }
+ fclose(fp);
+ fp = fopen(themefile, "w");
+ if (fp == NULL) {
+ warn_user(messages_get("gtkFileError"), themefile);
+ free(filecontent);
+ return true;
+ }
+ val = fwrite(filecontent, strlen(filecontent), 1, fp);
+ if (val == 0)
+ LOG(("empty write themelist"));
+ fclose(fp);
+ free(filecontent);
+ return true;
+ } else {
+ fp = fopen(themefile, "r");
+ if (fp == NULL) {
+ warn_user(messages_get("gtkFileError"), themefile);
+ return false;
+ }
+ while (fgets(buf, sizeof(buf), fp) != NULL) {
+ buf[strlen(buf) - 1] = '\0';
+ /* "\n\0" -> "\0\0" */
+ if (strcmp(buf, themename) == 0) {
+ fclose(fp);
+ return false;
+ }
+ }
+ fclose(fp);
+ return true;
+ }
+
+}
+
+/**
+ * sets the images for a particular scaffolding according to the current theme
+ */
+
+void nsgtk_theme_implement(struct gtk_scaffolding *g)
+{
+ struct nsgtk_theme *theme[IMAGE_SET_COUNT];
+ int i;
+ struct nsgtk_button_connect *button;
+ struct gtk_search *search;
+
+ for (i = 0; i <= IMAGE_SET_POPUP_MENU; i++)
+ theme[i] = nsgtk_theme_load(GTK_ICON_SIZE_MENU);
+
+ theme[IMAGE_SET_BUTTONS] =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ if ((i == URL_BAR_ITEM) || (i == THROBBER_ITEM) ||
+ (i == WEBSEARCH_ITEM))
+ continue;
+ button = nsgtk_scaffolding_button(g, i);
+ if (button == NULL)
+ continue;
+ /* gtk_image_menu_item_set_image accepts NULL image */
+ if ((button->main != NULL) &&
+ (theme[IMAGE_SET_MAIN_MENU] != NULL)) {
+ gtk_image_menu_item_set_image(button->main,
+ GTK_WIDGET(
+ theme[IMAGE_SET_MAIN_MENU]->
+ image[i]));
+ gtk_widget_show_all(GTK_WIDGET(button->main));
+ }
+ if ((button->rclick != NULL) &&
+ (theme[IMAGE_SET_RCLICK_MENU] != NULL)) {
+ gtk_image_menu_item_set_image(button->rclick,
+ GTK_WIDGET(
+ theme[IMAGE_SET_RCLICK_MENU]->
+ image[i]));
+ gtk_widget_show_all(GTK_WIDGET(button->rclick));
+ }
+ if ((button->popup != NULL) &&
+ (theme[IMAGE_SET_POPUP_MENU] != NULL)) {
+ gtk_image_menu_item_set_image(button->popup,
+ GTK_WIDGET(
+ theme[IMAGE_SET_POPUP_MENU]->
+ image[i]));
+ gtk_widget_show_all(GTK_WIDGET(button->popup));
+ }
+ if ((button->location != -1) && (button->button != NULL) &&
+ (theme[IMAGE_SET_BUTTONS] != NULL)) {
+ gtk_tool_button_set_icon_widget(
+ GTK_TOOL_BUTTON(button->button),
+ GTK_WIDGET(
+ theme[IMAGE_SET_BUTTONS]->
+ image[i]));
+ gtk_widget_show_all(GTK_WIDGET(button->button));
+ }
+ }
+
+ /* set search bar images */
+ search = nsgtk_scaffolding_search(g);
+ if ((search != NULL) && (theme[IMAGE_SET_MAIN_MENU] != NULL)) {
+ /* gtk_tool_button_set_icon_widget accepts NULL image */
+ if (search->buttons[SEARCH_BACK_BUTTON] != NULL) {
+ gtk_tool_button_set_icon_widget(
+ search->buttons[SEARCH_BACK_BUTTON],
+ GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->
+ searchimage[SEARCH_BACK_BUTTON]));
+ gtk_widget_show_all(GTK_WIDGET(
+ search->buttons[SEARCH_BACK_BUTTON]));
+ }
+ if (search->buttons[SEARCH_FORWARD_BUTTON] != NULL) {
+ gtk_tool_button_set_icon_widget(
+ search->buttons[SEARCH_FORWARD_BUTTON],
+ GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->
+ searchimage[SEARCH_FORWARD_BUTTON]));
+ gtk_widget_show_all(GTK_WIDGET(
+ search->buttons[
+ SEARCH_FORWARD_BUTTON]));
+ }
+ if (search->buttons[SEARCH_CLOSE_BUTTON] != NULL) {
+ gtk_tool_button_set_icon_widget(
+ search->buttons[SEARCH_CLOSE_BUTTON],
+ GTK_WIDGET(theme[IMAGE_SET_MAIN_MENU]->
+ searchimage[SEARCH_CLOSE_BUTTON]));
+ gtk_widget_show_all(GTK_WIDGET(
+ search->buttons[SEARCH_CLOSE_BUTTON]));
+ }
+ }
+ for (i = 0; i < IMAGE_SET_COUNT; i++)
+ if (theme[i] != NULL)
+ free(theme[i]);
+}
+
+/**
+ * creates a set of images to add to buttons / menus
+ * loads images from cache, calling an update to the cache when necessary
+ * \return a struct nsgtk_theme is an array of images
+ */
+
+struct nsgtk_theme *nsgtk_theme_load(GtkIconSize s)
+{
+ if (current_theme_name == NULL)
+ return nsgtk_theme_default(s);
+
+ struct nsgtk_theme *theme = malloc(sizeof(struct nsgtk_theme));
+ if (theme == NULL)
+ return theme;
+
+ if ((theme_cache_menu == NULL) || (theme_cache_toolbar == NULL))
+ nsgtk_theme_prepare();
+
+ /* load theme from cache */
+ struct nsgtk_theme_cache *cachetheme = (s == GTK_ICON_SIZE_MENU) ?
+ theme_cache_menu : theme_cache_toolbar;
+ if (cachetheme == NULL)
+ return NULL;
+
+#define SET_BUTTON_IMAGE(p, q, r)\
+ if (p->image[q##_BUTTON] != NULL)\
+ r->image[q##_BUTTON] = GTK_IMAGE(gtk_image_new_from_pixbuf(\
+ p->image[q##_BUTTON]));\
+ else\
+ r->image[q##_BUTTON] = nsgtk_theme_image_default(\
+ q##_BUTTON, s);
+
+ SET_BUTTON_IMAGE(cachetheme, BACK, theme)
+ SET_BUTTON_IMAGE(cachetheme, HISTORY, theme)
+ SET_BUTTON_IMAGE(cachetheme, FORWARD, theme)
+ SET_BUTTON_IMAGE(cachetheme, STOP, theme)
+ SET_BUTTON_IMAGE(cachetheme, RELOAD, theme)
+ SET_BUTTON_IMAGE(cachetheme, HOME, theme)
+ SET_BUTTON_IMAGE(cachetheme, NEWWINDOW, theme)
+ SET_BUTTON_IMAGE(cachetheme, NEWTAB, theme)
+ SET_BUTTON_IMAGE(cachetheme, OPENFILE, theme)
+ SET_BUTTON_IMAGE(cachetheme, CLOSETAB, theme)
+ SET_BUTTON_IMAGE(cachetheme, CLOSEWINDOW, theme)
+ SET_BUTTON_IMAGE(cachetheme, SAVEPAGE, theme)
+ SET_BUTTON_IMAGE(cachetheme, PRINTPREVIEW, theme)
+ SET_BUTTON_IMAGE(cachetheme, PRINT, theme)
+ SET_BUTTON_IMAGE(cachetheme, QUIT, theme)
+ SET_BUTTON_IMAGE(cachetheme, CUT, theme)
+ SET_BUTTON_IMAGE(cachetheme, COPY, theme)
+ SET_BUTTON_IMAGE(cachetheme, PASTE, theme)
+ SET_BUTTON_IMAGE(cachetheme, DELETE, theme)
+ SET_BUTTON_IMAGE(cachetheme, SELECTALL, theme)
+ SET_BUTTON_IMAGE(cachetheme, PREFERENCES, theme)
+ SET_BUTTON_IMAGE(cachetheme, ZOOMPLUS, theme)
+ SET_BUTTON_IMAGE(cachetheme, ZOOMMINUS, theme)
+ SET_BUTTON_IMAGE(cachetheme, ZOOMNORMAL, theme)
+ SET_BUTTON_IMAGE(cachetheme, FULLSCREEN, theme)
+ SET_BUTTON_IMAGE(cachetheme, VIEWSOURCE, theme)
+ SET_BUTTON_IMAGE(cachetheme, CONTENTS, theme)
+ SET_BUTTON_IMAGE(cachetheme, ABOUT, theme)
+ SET_BUTTON_IMAGE(cachetheme, PDF, theme)
+ SET_BUTTON_IMAGE(cachetheme, PLAINTEXT, theme)
+ SET_BUTTON_IMAGE(cachetheme, DRAWFILE, theme)
+ SET_BUTTON_IMAGE(cachetheme, POSTSCRIPT, theme)
+ SET_BUTTON_IMAGE(cachetheme, FIND, theme)
+ SET_BUTTON_IMAGE(cachetheme, DOWNLOADS, theme)
+ SET_BUTTON_IMAGE(cachetheme, SAVEWINDOWSIZE, theme)
+ SET_BUTTON_IMAGE(cachetheme, TOGGLEDEBUGGING, theme)
+ SET_BUTTON_IMAGE(cachetheme, SAVEBOXTREE, theme)
+ SET_BUTTON_IMAGE(cachetheme, SAVEDOMTREE, theme)
+ SET_BUTTON_IMAGE(cachetheme, LOCALHISTORY, theme)
+ SET_BUTTON_IMAGE(cachetheme, GLOBALHISTORY, theme)
+ SET_BUTTON_IMAGE(cachetheme, ADDBOOKMARKS, theme)
+ SET_BUTTON_IMAGE(cachetheme, SHOWBOOKMARKS, theme)
+ SET_BUTTON_IMAGE(cachetheme, OPENLOCATION, theme)
+ SET_BUTTON_IMAGE(cachetheme, NEXTTAB, theme)
+ SET_BUTTON_IMAGE(cachetheme, PREVTAB, theme)
+ SET_BUTTON_IMAGE(cachetheme, GUIDE, theme)
+ SET_BUTTON_IMAGE(cachetheme, INFO, theme)
+#undef SET_BUTTON_IMAGE
+#define SET_BUTTON_IMAGE(p, q, qq, r)\
+ if (qq->searchimage[SEARCH_##p##_BUTTON] != NULL)\
+ r->searchimage[SEARCH_##p##_BUTTON] =\
+ GTK_IMAGE(gtk_image_new_from_pixbuf(\
+ qq->searchimage[\
+ SEARCH_##p##_BUTTON]));\
+ else if (qq->image[q##_BUTTON] != NULL)\
+ r->searchimage[SEARCH_##p##_BUTTON] =\
+ GTK_IMAGE(gtk_image_new_from_pixbuf(\
+ qq->image[q##_BUTTON]));\
+ else\
+ r->searchimage[SEARCH_##p##_BUTTON] =\
+ nsgtk_theme_image_default(\
+ PLACEHOLDER_BUTTON + SEARCH_##p##_BUTTON, s);
+
+ SET_BUTTON_IMAGE(BACK, BACK, cachetheme, theme)
+ SET_BUTTON_IMAGE(FORWARD, FORWARD, cachetheme, theme)
+ SET_BUTTON_IMAGE(CLOSE, CLOSEWINDOW, cachetheme, theme)
+#undef SET_BUTTON_IMAGE
+ return theme;
+}
+
+/**
+ * caches individual theme images from file
+ * \param i the toolbar button reference
+ * \param filename the image file name
+ * \param path the path to the theme folder
+ */
+void nsgtk_theme_cache_image(nsgtk_toolbar_button i, const char *filename,
+ const char *path)
+{
+ char fullpath[strlen(filename) + strlen(path) + 1];
+ sprintf(fullpath, "%s%s", path, filename);
+ if (theme_cache_toolbar != NULL)
+ theme_cache_toolbar->image[i] =
+ gdk_pixbuf_new_from_file_at_size(fullpath,
+ 24, 24, NULL);
+ if (theme_cache_menu != NULL)
+ theme_cache_menu->image[i] = gdk_pixbuf_new_from_file_at_size(
+ fullpath, 16, 16, NULL);
+}
+
+void nsgtk_theme_cache_searchimage(nsgtk_search_buttons i,
+ const char *filename, const char *path)
+{
+ char fullpath[strlen(filename) + strlen(path) + 1];
+ sprintf(fullpath, "%s%s", path, filename);
+ if (theme_cache_toolbar != NULL)
+ theme_cache_toolbar->searchimage[i] =
+ gdk_pixbuf_new_from_file_at_size(fullpath,
+ 24, 24, NULL);
+ if (theme_cache_menu != NULL)
+ theme_cache_menu->searchimage[i] =
+ gdk_pixbuf_new_from_file_at_size(fullpath,
+ 16, 16, NULL);
+}
+
+/**
+ * caches theme images from file as pixbufs
+ */
+void nsgtk_theme_prepare(void)
+{
+ if (current_theme_name == NULL)
+ return;
+ if (theme_cache_menu == NULL)
+ theme_cache_menu = malloc(sizeof(struct nsgtk_theme_cache));
+ if (theme_cache_toolbar == NULL)
+ theme_cache_toolbar = malloc(sizeof(struct nsgtk_theme_cache));
+ size_t len = strlen(res_dir_location) + SLEN("/themes/") +
+ strlen(current_theme_name) + 1;
+ char path[len];
+ snprintf(path, len, "%sthemes/%s/", res_dir_location,
+ current_theme_name);
+#define CACHE_IMAGE(p, q, r)\
+ nsgtk_theme_cache_image(p##_BUTTON, #q ".png", r)
+
+ CACHE_IMAGE(BACK, back, path);
+ CACHE_IMAGE(HISTORY, history, path);
+ CACHE_IMAGE(FORWARD, forward, path);
+ CACHE_IMAGE(STOP, stop, path);
+ CACHE_IMAGE(RELOAD, reload, path);
+ CACHE_IMAGE(HOME, home, path);
+ CACHE_IMAGE(NEWWINDOW, newwindow, path);
+ CACHE_IMAGE(NEWTAB, newtab, path);
+ CACHE_IMAGE(OPENFILE, openfile, path);
+ CACHE_IMAGE(CLOSETAB, closetab, path);
+ CACHE_IMAGE(CLOSEWINDOW, closewindow, path);
+ CACHE_IMAGE(SAVEPAGE, savepage, path);
+ CACHE_IMAGE(PRINTPREVIEW, printpreview, path);
+ CACHE_IMAGE(PRINT, print, path);
+ CACHE_IMAGE(QUIT, quit, path);
+ CACHE_IMAGE(CUT, cut, path);
+ CACHE_IMAGE(COPY, copy, path);
+ CACHE_IMAGE(PASTE, paste, path);
+ CACHE_IMAGE(DELETE, delete, path);
+ CACHE_IMAGE(SELECTALL, selectall, path);
+ CACHE_IMAGE(PREFERENCES, preferences, path);
+ CACHE_IMAGE(ZOOMPLUS, zoomplus, path);
+ CACHE_IMAGE(ZOOMMINUS, zoomminus, path);
+ CACHE_IMAGE(ZOOMNORMAL, zoomnormal, path);
+ CACHE_IMAGE(FULLSCREEN, fullscreen, path);
+ CACHE_IMAGE(VIEWSOURCE, viewsource, path);
+ CACHE_IMAGE(CONTENTS, helpcontents, path);
+ CACHE_IMAGE(ABOUT, helpabout, path);
+ CACHE_IMAGE(PDF, pdf, path);
+ CACHE_IMAGE(PLAINTEXT, plaintext, path);
+ CACHE_IMAGE(DRAWFILE, drawfile, path);
+ CACHE_IMAGE(POSTSCRIPT, postscript, path);
+ CACHE_IMAGE(FIND, find, path);
+ CACHE_IMAGE(DOWNLOADS, downloads, path);
+ CACHE_IMAGE(SAVEWINDOWSIZE, savewindowsize, path);
+ CACHE_IMAGE(TOGGLEDEBUGGING, toggledebugging, path);
+ CACHE_IMAGE(SAVEBOXTREE, boxtree, path);
+ CACHE_IMAGE(SAVEDOMTREE, domtree, path);
+ CACHE_IMAGE(LOCALHISTORY, localhistory, path);
+ CACHE_IMAGE(GLOBALHISTORY, globalhistory, path);
+ CACHE_IMAGE(ADDBOOKMARKS, addbookmarks, path);
+ CACHE_IMAGE(SHOWBOOKMARKS, showbookmarks, path);
+ CACHE_IMAGE(OPENLOCATION, openlocation, path);
+ CACHE_IMAGE(NEXTTAB, nexttab, path);
+ CACHE_IMAGE(PREVTAB, prevtab, path);
+ CACHE_IMAGE(GUIDE, helpguide, path);
+ CACHE_IMAGE(INFO, helpinfo, path);
+#undef CACHE_IMAGE
+#define CACHE_IMAGE(p, q, r)\
+ nsgtk_theme_cache_searchimage(p, #q ".png", r);
+
+ CACHE_IMAGE(SEARCH_BACK_BUTTON, searchback, path);
+ CACHE_IMAGE(SEARCH_FORWARD_BUTTON, searchforward, path);
+ CACHE_IMAGE(SEARCH_CLOSE_BUTTON, searchclose, path);
+#undef CACHE_IMAGE
+}
+
+/**
+ * returns default image for buttons / menu items from gtk stock items
+ * \param i button reference
+ */
+
+GtkImage *nsgtk_theme_image_default(nsgtk_toolbar_button i, GtkIconSize s)
+{
+ char *imagefile;
+ GtkImage *image;
+ switch(i) {
+#define BUTTON_IMAGE(p, q)\
+ case p##_BUTTON:\
+ return GTK_IMAGE(gtk_image_new_from_stock(#q, s))
+
+ BUTTON_IMAGE(BACK, gtk-go-back);
+ case HISTORY_BUTTON: {
+ size_t len = SLEN("arrow_down_8x32.png") +
+ strlen(res_dir_location) + 1;
+ imagefile = malloc(len);
+ if (imagefile == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ snprintf(imagefile, len, "%sarrow_down_8x32.png",
+ res_dir_location);
+ image = GTK_IMAGE(gtk_image_new_from_file(imagefile));
+ free(imagefile);
+ return image;
+ }
+ BUTTON_IMAGE(FORWARD, gtk-go-forward);
+ BUTTON_IMAGE(STOP, gtk-stop);
+ BUTTON_IMAGE(RELOAD, gtk-refresh);
+ BUTTON_IMAGE(HOME, gtk-home);
+ BUTTON_IMAGE(NEWWINDOW, gtk-new);
+ BUTTON_IMAGE(NEWTAB, gtk-new);
+ BUTTON_IMAGE(OPENFILE, gtk-open);
+ BUTTON_IMAGE(CLOSETAB, gtk-close);
+ BUTTON_IMAGE(CLOSEWINDOW, gtk-close);
+ BUTTON_IMAGE(SAVEPAGE, gtk-save-as);
+ BUTTON_IMAGE(PRINTPREVIEW, gtk-print-preview);
+ BUTTON_IMAGE(PRINT, gtk-print);
+ BUTTON_IMAGE(QUIT, gtk-quit);
+ BUTTON_IMAGE(CUT, gtk-cut);
+ BUTTON_IMAGE(COPY, gtk-copy);
+ BUTTON_IMAGE(PASTE, gtk-paste);
+ BUTTON_IMAGE(DELETE, gtk-delete);
+ BUTTON_IMAGE(SELECTALL, gtk-select-all);
+ BUTTON_IMAGE(FIND, gtk-find);
+ BUTTON_IMAGE(PREFERENCES, gtk-preferences);
+ BUTTON_IMAGE(ZOOMPLUS, gtk-zoom-in);
+ BUTTON_IMAGE(ZOOMMINUS, gtk-zoom-out);
+ BUTTON_IMAGE(ZOOMNORMAL, gtk-zoom-100);
+ BUTTON_IMAGE(FULLSCREEN, gtk-fullscreen);
+ BUTTON_IMAGE(VIEWSOURCE, gtk-index);
+ BUTTON_IMAGE(CONTENTS, gtk-help);
+ BUTTON_IMAGE(ABOUT, gtk-about);
+#undef BUTTON_IMAGE
+ case (PLACEHOLDER_BUTTON + SEARCH_BACK_BUTTON):
+ return GTK_IMAGE(gtk_image_new_from_stock("gtk-go-back", s));
+ case (PLACEHOLDER_BUTTON + SEARCH_FORWARD_BUTTON):
+ return GTK_IMAGE(gtk_image_new_from_stock("gtk-go-forward",
+ s));
+ case (PLACEHOLDER_BUTTON + SEARCH_CLOSE_BUTTON):
+ return GTK_IMAGE(gtk_image_new_from_stock("gtk-close", s));
+ default: {
+ size_t len = SLEN("themes/Alpha.png") +
+ strlen(res_dir_location) + 1;
+ imagefile = malloc(len);
+ if (imagefile == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ snprintf(imagefile, len, "%sthemes/Alpha.png",
+ res_dir_location);
+ image = GTK_IMAGE(
+ gtk_image_new_from_file(imagefile));
+ free(imagefile);
+ return image;
+ }
+ }
+}
+
+
+#ifdef WITH_THEME_INSTALL
+/**
+ * when CONTENT_THEME needs handling call this function
+ */
+void theme_install_start(struct content *c)
+{
+ assert(c);
+ assert(c->type == CONTENT_THEME);
+
+ /* stop theme sitting in memory cache */
+ c->fresh = false;
+ if (!content_add_user(c, theme_install_callback, 0, 0)) {
+ warn_user("NoMemory", 0);
+ return;
+ }
+}
+
+
+/**
+ * Callback for fetchcache() for theme install fetches.
+ */
+
+void theme_install_callback(content_msg msg, struct content *c,
+ intptr_t p1, intptr_t p2, union content_msg_data data)
+{
+ switch (msg) {
+ case CONTENT_MSG_READY:
+ break;
+
+ case CONTENT_MSG_DONE:
+ theme_install_content = c;
+ if (!theme_install_read(c->source_data, c->source_size))
+ warn_user("ThemeInvalid", 0);
+ break;
+
+ case CONTENT_MSG_ERROR:
+ warn_user(data.error, 0);
+ break;
+
+ case CONTENT_MSG_STATUS:
+ break;
+
+ case CONTENT_MSG_LOADING:
+ case CONTENT_MSG_REFORMAT:
+ case CONTENT_MSG_REDRAW:
+ case CONTENT_MSG_NEWPTR:
+ case CONTENT_MSG_LAUNCH:
+ case CONTENT_MSG_AUTH:
+ default:
+ assert(0);
+ break;
+ }
+}
+
+/**
+ * handler saves theme data content as a local theme
+ */
+
+bool theme_install_read(const char *data, unsigned long len)
+{
+ char *filename, *newfilename;
+ size_t namelen;
+ int handle = g_file_open_tmp("nsgtkthemeXXXXXX", &filename, NULL);
+ if (handle == -1) {
+ warn_user(messages_get("gtkFileError"),
+ "temporary theme file");
+ }
+ ssize_t written = write(handle, data, len);
+ close(handle);
+ if ((unsigned)written != len)
+ return false;
+
+ /* get name of theme; set as dirname */
+ namelen = SLEN("themes/") + strlen(res_dir_location) + 1;
+ char dirname[namelen];
+ snprintf(dirname, namelen, "%sthemes/", res_dir_location);
+
+ /* save individual files in theme */
+ newfilename = container_extract_theme(filename, dirname);
+ g_free(filename);
+ if (newfilename == NULL)
+ return false;
+ nsgtk_theme_add(newfilename);
+ free(newfilename);
+
+ return true;
+}
+#endif
+
+/**
+ * loads the set of default images for the toolbar / menus
+ */
+
+struct nsgtk_theme *nsgtk_theme_default(GtkIconSize s)
+{
+ struct nsgtk_theme *theme = malloc(sizeof(struct nsgtk_theme));
+ if (theme == NULL) {
+ warn_user("NoMemory", 0);
+ return NULL;
+ }
+ for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON +
+ SEARCH_BUTTONS_COUNT; i++)
+ theme->image[i] = nsgtk_theme_image_default(i, s);
+ return theme;
+}
+
diff --git a/gtk/gtk_theme.h b/gtk/gtk_theme.h
new file mode 100644
index 000000000..833379d36
--- /dev/null
+++ b/gtk/gtk_theme.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_GTK_THEME_H_
+#define _NETSURF_GTK_THEME_H_
+
+#include <gtk/gtk.h>
+#include "gtk/gtk_scaffolding.h"
+
+typedef enum search_buttons {
+ SEARCH_BACK_BUTTON = 0,
+ SEARCH_FORWARD_BUTTON,
+ SEARCH_CLOSE_BUTTON,
+ SEARCH_BUTTONS_COUNT
+} nsgtk_search_buttons;
+
+struct nsgtk_theme {
+ GtkImage *image[PLACEHOLDER_BUTTON];
+ GtkImage *searchimage[SEARCH_BUTTONS_COUNT];
+ /* apng throbber element */
+};
+
+struct nsgtk_theme *nsgtk_theme_load(GtkIconSize s);
+void nsgtk_theme_add(const char *themename);
+void nsgtk_theme_init(void);
+void nsgtk_theme_prepare(void);
+void nsgtk_theme_implement(struct gtk_scaffolding *g);
+char *nsgtk_theme_name(void);
+void nsgtk_theme_set_name(char *name);
+
+#endif
diff --git a/gtk/gtk_toolbar.c b/gtk/gtk_toolbar.c
new file mode 100644
index 000000000..20cfbd812
--- /dev/null
+++ b/gtk/gtk_toolbar.c
@@ -0,0 +1,1102 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtk/gtk.h>
+#include "desktop/searchweb.h"
+#include "gtk/gtk_toolbar.h"
+#include "gtk/gtk_gui.h"
+#include "gtk/gtk_scaffolding.h"
+#include "gtk/gtk_search.h"
+#include "gtk/gtk_theme.h"
+#include "gtk/gtk_throbber.h"
+#include "gtk/gtk_window.h"
+#include "gtk/sexy_icon_entry.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
+
+static GtkTargetEntry entry = {(char *)"nsgtk_button_data",
+ GTK_TARGET_SAME_APP, 0};
+
+static bool edit_mode = false;
+
+struct nsgtk_toolbar_custom_store {
+ GtkWidget *window;
+ GtkWidget *store_buttons[PLACEHOLDER_BUTTON];
+ GtkWidget *widgetvbox;
+ GtkWidget *currentbar;
+ char numberh; /* current horizontal location while adding */
+ GladeXML *glade; /* button widgets to store */
+ int buttonlocations[PLACEHOLDER_BUTTON];
+ int currentbutton;
+ bool fromstore;
+};
+/* the number of buttons that fit in the width of the store window */
+#define NSGTK_STORE_WIDTH 6
+
+/* the 'standard' width of a button that makes sufficient of its label
+visible */
+#define NSGTK_BUTTON_WIDTH 111
+
+/* the 'standard' height of a button that fits as many toolbars as
+possible into the store */
+#define NSGTK_BUTTON_HEIGHT 70
+
+/* the 'normal' width of the websearch bar */
+#define NSGTK_WEBSEARCH_WIDTH 150
+
+static struct nsgtk_toolbar_custom_store store;
+static struct nsgtk_toolbar_custom_store *window = &store;
+
+static void nsgtk_toolbar_close(nsgtk_scaffolding *g);
+static void nsgtk_toolbar_window_open(nsgtk_scaffolding *g);
+static void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g);
+static void nsgtk_toolbar_add_item_to_toolbar(nsgtk_scaffolding *g, int i,
+ struct nsgtk_theme *theme);
+static bool nsgtk_toolbar_add_store_widget(GtkWidget *widget);
+static gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *context,
+ gint x, gint y, guint time, gpointer data);
+static gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc, gint x, gint y, guint time, gpointer data);
+static gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext
+ *drag_context, gint x, gint y, guint time, gpointer data);
+gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, guint time, gpointer data);
+static gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext
+ *gdc, gint x, gint y, GtkSelectionData *selection, guint info,
+ guint time, gpointer data);
+static void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint
+ time, gpointer data);
+static gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event,
+ gpointer data);
+static gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data);
+static gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data);
+static gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data);
+static void nsgtk_toolbar_cast(nsgtk_scaffolding *g);
+static GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i, struct nsgtk_theme *theme);
+static void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i);
+static void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i);
+static void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data);
+static nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location(
+ nsgtk_scaffolding *g, int i);
+
+/**
+ * change behaviour of scaffoldings while editing toolbar; all buttons as
+ * well as window clicks are desensitized; then buttons in the front window
+ * are changed to movable buttons
+ */
+void nsgtk_toolbar_customization_init(nsgtk_scaffolding *g)
+{
+ int i;
+ nsgtk_scaffolding *list = scaf_list;
+ edit_mode = true;
+
+ while (list) {
+ g_signal_handler_block(GTK_WIDGET(
+ nsgtk_window_get_drawing_area(
+ nsgtk_scaffolding_top_level(list))),
+ nsgtk_window_get_signalhandler(
+ nsgtk_scaffolding_top_level(list),
+ NSGTK_WINDOW_SIGNAL_CLICK));
+ g_signal_handler_block(GTK_WIDGET(
+ nsgtk_window_get_drawing_area(
+ nsgtk_scaffolding_top_level(list))),
+ nsgtk_window_get_signalhandler(
+ nsgtk_scaffolding_top_level(list),
+ NSGTK_WINDOW_SIGNAL_REDRAW));
+ gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_drawing_area(
+ nsgtk_scaffolding_top_level(list))),
+ GTK_STATE_NORMAL, &((GdkColor)
+ {0, 0xEEEE, 0xEEEE, 0xEEEE}));
+
+ if (list == g) {
+ list = nsgtk_scaffolding_iterate(list);
+ continue;
+ }
+ /* set sensitive for all gui_windows save g */
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_window(
+ list)), FALSE);
+ list = nsgtk_scaffolding_iterate(list);
+ }
+ /* set sensitive for all of g save toolbar */
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)),
+ FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)),
+ FALSE);
+
+ /* set editable aspect for toolbar */
+ gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)),
+ nsgtk_toolbar_clear_toolbar, g);
+ nsgtk_toolbar_set_physical(g);
+ /* memorize button locations, set editable */
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ window->buttonlocations[i] = nsgtk_scaffolding_button(g, i)
+ ->location;
+ if ((window->buttonlocations[i] == -1) || (i == URL_BAR_ITEM))
+ continue;
+ gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(
+ nsgtk_scaffolding_button(g, i)->button), TRUE);
+ gtk_drag_source_set(GTK_WIDGET(nsgtk_scaffolding_button(
+ g, i)->button), GDK_BUTTON1_MASK, &entry, 1,
+ GDK_ACTION_COPY);
+ nsgtk_toolbar_temp_connect(g, i);
+ }
+
+ /* add move button listeners */
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
+ "drag-drop", G_CALLBACK(nsgtk_toolbar_data), g);
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
+ "drag-data-received", G_CALLBACK(
+ nsgtk_toolbar_move_complete), g);
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
+ "drag-motion", G_CALLBACK(nsgtk_toolbar_action), g);
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
+ "drag-leave", G_CALLBACK(
+ nsgtk_toolbar_clear), g);
+
+ /* set data types */
+ gtk_drag_dest_set(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)),
+ GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP,
+ &entry, 1, GDK_ACTION_COPY);
+
+ /* open toolbar window */
+ nsgtk_toolbar_window_open(g);
+}
+
+/**
+ * create store window
+ */
+void nsgtk_toolbar_window_open(nsgtk_scaffolding *g)
+{
+ int x = 0, y = 0;
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ nsgtk_toolbar_cancel_clicked(NULL, g);
+ return;
+ }
+ window->glade = glade_xml_new(glade_toolbar_file_location,
+ "toolbarwindow", NULL);
+ if (window->glade == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ nsgtk_toolbar_cancel_clicked(NULL, g);
+ }
+ glade_xml_signal_autoconnect(window->glade);
+
+#define GET_TOOLWIDGET(p, q, r, s) r->p = glade_xml_get_widget(r->s, #q);\
+ if (r->p == NULL) {\
+ warn_user(messages_get("NoMemory"), 0);\
+ nsgtk_toolbar_cancel_clicked(NULL, g);\
+ return;\
+ }
+
+ GET_TOOLWIDGET(window, toolbarwindow, window, glade)
+ GET_TOOLWIDGET(widgetvbox, widgetvbox, window, glade)
+#undef GET_TOOLWIDGET
+
+ window->numberh = NSGTK_STORE_WIDTH; /* preset to width [in buttons] of */
+ /* store to cause creation of a new toolbar */
+ window->currentbutton = -1;
+ /* load toolbuttons */
+ /* add toolbuttons to window */
+ /* set event handlers */
+ for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ if (i == URL_BAR_ITEM)
+ continue;
+ window->store_buttons[i] =
+ nsgtk_toolbar_make_widget(g, i, theme);
+ if (window->store_buttons[i] == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ continue;
+ }
+ nsgtk_toolbar_add_store_widget(window->store_buttons[i]);
+ g_signal_connect(window->store_buttons[i], "drag-data-get",
+ G_CALLBACK(
+ nsgtk_scaffolding_button(g, i)->dataplus), g);
+ }
+ free(theme);
+ gtk_window_set_transient_for(GTK_WINDOW(window->window),
+ nsgtk_scaffolding_window(g));
+ gtk_window_set_title(GTK_WINDOW(window->window), messages_get(
+ "gtkToolBarTitle"));
+ gtk_window_set_accept_focus(GTK_WINDOW(window->window), FALSE);
+ gtk_drag_dest_set(GTK_WIDGET(window->window), GTK_DEST_DEFAULT_MOTION |
+ GTK_DEST_DEFAULT_DROP, &entry, 1, GDK_ACTION_COPY);
+ gtk_widget_show_all(window->window);
+ gtk_window_set_position(GTK_WINDOW(window->window),
+ GTK_WIN_POS_CENTER_ON_PARENT);
+ gtk_window_get_position(nsgtk_scaffolding_window(g), &x, &y);
+ gtk_window_move(GTK_WINDOW(window->window), x, y + 100);
+ g_signal_connect(glade_xml_get_widget(window->glade, "cancelbutton"),
+ "clicked", G_CALLBACK(
+ nsgtk_toolbar_cancel_clicked), g);
+ g_signal_connect(glade_xml_get_widget(window->glade, "okbutton"),
+ "clicked", G_CALLBACK(nsgtk_toolbar_persist), g);
+ g_signal_connect(glade_xml_get_widget(window->glade, "resetbutton"),
+ "clicked", G_CALLBACK(nsgtk_toolbar_reset), g);
+ g_signal_connect(window->window, "delete-event",
+ G_CALLBACK(nsgtk_toolbar_delete), g);
+ g_signal_connect(window->window, "drag-drop",
+ G_CALLBACK(nsgtk_toolbar_store_return), g);
+ g_signal_connect(window->window, "drag-motion",
+ G_CALLBACK(nsgtk_toolbar_store_action), g);
+}
+
+/**
+ * when titlebar / alt-F4 window close event happens
+ */
+gboolean nsgtk_toolbar_delete(GtkWidget *widget, GdkEvent *event,
+ gpointer data)
+{
+ edit_mode = false;
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ /* reset g->buttons->location */
+ for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ nsgtk_scaffolding_button(g, i)->location =
+ window->buttonlocations[i];
+ }
+ nsgtk_toolbar_set_physical(g);
+ nsgtk_toolbar_connect_all(g);
+ nsgtk_toolbar_close(g);
+ nsgtk_scaffolding_set_sensitivity(g);
+ gtk_widget_destroy(window->window);
+ return TRUE;
+}
+
+/**
+ * when cancel button is clicked
+ */
+gboolean nsgtk_toolbar_cancel_clicked(GtkWidget *widget, gpointer data)
+{
+ edit_mode = false;
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ /* reset g->buttons->location */
+ for (int i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ nsgtk_scaffolding_button(g, i)->location =
+ window->buttonlocations[i];
+ }
+ nsgtk_toolbar_set_physical(g);
+ nsgtk_toolbar_connect_all(g);
+ nsgtk_toolbar_close(g);
+ nsgtk_scaffolding_set_sensitivity(g);
+ gtk_widget_destroy(window->window);
+ return TRUE;
+}
+
+/**
+ * when 'save settings' button is clicked
+ */
+gboolean nsgtk_toolbar_persist(GtkWidget *widget, gpointer data)
+{
+ edit_mode = false;
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ /* save state to file, update toolbars for all windows */
+ nsgtk_toolbar_customization_save(g);
+ nsgtk_toolbar_cast(g);
+ nsgtk_toolbar_set_physical(g);
+ nsgtk_toolbar_close(g);
+ gtk_widget_destroy(window->window);
+ return TRUE;
+}
+
+/**
+ * when 'reload defaults' button is clicked
+ */
+gboolean nsgtk_toolbar_reset(GtkWidget *widget, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ int i;
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
+ nsgtk_scaffolding_button(g, i)->location =
+ (i <= THROBBER_ITEM) ? i : -1;
+ nsgtk_toolbar_set_physical(g);
+ for (i = BACK_BUTTON; i <= THROBBER_ITEM; i++) {
+ if (i == URL_BAR_ITEM)
+ continue;
+ gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(
+ nsgtk_scaffolding_button(g, i)->button), TRUE);
+ gtk_drag_source_set(GTK_WIDGET(
+ nsgtk_scaffolding_button(g, i)->button),
+ GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY);
+ nsgtk_toolbar_temp_connect(g, i);
+ }
+ return TRUE;
+}
+
+/**
+ * set toolbar logical -> physical; physically visible toolbar buttons are made
+ * to correspond to the logically stored schema in terms of location
+ * visibility etc
+ */
+void nsgtk_toolbar_set_physical(nsgtk_scaffolding *g)
+{
+ int i;
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return;
+ }
+ /* simplest is to clear the toolbar then reload it from memory */
+ gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)),
+ nsgtk_toolbar_clear_toolbar, g);
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
+ nsgtk_toolbar_add_item_to_toolbar(g, i, theme);
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(g)));
+ free(theme);
+}
+
+/**
+ * cleanup code physical update of all toolbars; resensitize
+ * \param g the 'front' scaffolding that called customize
+ */
+void nsgtk_toolbar_close(nsgtk_scaffolding *g)
+{
+ int i;
+ nsgtk_scaffolding *list = scaf_list;
+ while (list) {
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ continue;
+ }
+ /* clear toolbar */
+ gtk_container_foreach(GTK_CONTAINER(nsgtk_scaffolding_toolbar(
+ list)), nsgtk_toolbar_clear_toolbar, list);
+ /* then add items */
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ nsgtk_toolbar_add_item_to_toolbar(list, i, theme);
+ }
+ nsgtk_toolbar_connect_all(list);
+ gtk_widget_show_all(GTK_WIDGET(nsgtk_scaffolding_toolbar(
+ list)));
+ nsgtk_scaffolding_set_sensitivity(list);
+ gtk_widget_modify_bg(GTK_WIDGET(nsgtk_window_get_drawing_area(
+ nsgtk_scaffolding_top_level(list))),
+ GTK_STATE_NORMAL, &((GdkColor)
+ {0, 0xFFFF, 0xFFFF, 0xFFFF}));
+ g_signal_handler_unblock(GTK_WIDGET(
+ nsgtk_window_get_drawing_area(
+ nsgtk_scaffolding_top_level(list))),
+ nsgtk_window_get_signalhandler(
+ nsgtk_scaffolding_top_level(list),
+ NSGTK_WINDOW_SIGNAL_CLICK));
+ g_signal_handler_unblock(GTK_WIDGET(
+ nsgtk_window_get_drawing_area(
+ nsgtk_scaffolding_top_level(list))),
+ nsgtk_window_get_signalhandler(
+ nsgtk_scaffolding_top_level(list),
+ NSGTK_WINDOW_SIGNAL_REDRAW));
+ if ((gui_window_get_browser_window(nsgtk_scaffolding_top_level(
+ list))->current_content != NULL) &&
+ (gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list))->
+ current_content->url != NULL))
+ browser_window_refresh_url_bar(
+ gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list)),
+ gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list))->
+ current_content->url,
+ gui_window_get_browser_window(
+ nsgtk_scaffolding_top_level(list))->
+ frag_id);
+
+ if (list != g)
+ gtk_widget_set_sensitive(GTK_WIDGET(
+ nsgtk_scaffolding_window(list)), TRUE);
+ free(theme);
+ list = nsgtk_scaffolding_iterate(list);
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_notebook(g)),
+ TRUE);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_menu_bar(g)),
+ TRUE);
+ /* update favicon etc */
+ nsgtk_scaffolding_set_top_level(nsgtk_scaffolding_top_level(g));
+ if (search_web_ico())
+ gui_window_set_search_ico(search_web_ico());
+}
+
+/**
+ * callback function to iterate toolbar's widgets
+ */
+void nsgtk_toolbar_clear_toolbar(GtkWidget *widget, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ gtk_container_remove(GTK_CONTAINER(nsgtk_scaffolding_toolbar(g)), widget);
+}
+
+/**
+ * add item to toolbar
+ * \param g the scaffolding whose toolbar an item is added to
+ * \param i the location in the toolbar
+ * the function should be called, when multiple items are being added,
+ * in ascending order
+ */
+void nsgtk_toolbar_add_item_to_toolbar(nsgtk_scaffolding *g, int i,
+ struct nsgtk_theme *theme)
+{
+ int q;
+ for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++)
+ if (nsgtk_scaffolding_button(g, q)->location == i) {
+ nsgtk_scaffolding_button(g, q)->button = GTK_TOOL_ITEM(
+ nsgtk_toolbar_make_widget(g, q,
+ theme));
+ gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g),
+ nsgtk_scaffolding_button(g, q)->button,
+ i);
+ break;
+ }
+}
+
+/**
+ * physically add widgets to store window
+ */
+bool nsgtk_toolbar_add_store_widget(GtkWidget *widget)
+{
+ if (window->numberh >= NSGTK_STORE_WIDTH) {
+ window->currentbar = gtk_toolbar_new();
+ if (window->currentbar == NULL) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ gtk_toolbar_set_style(GTK_TOOLBAR(window->currentbar),
+ GTK_TOOLBAR_BOTH);
+ gtk_toolbar_set_icon_size(GTK_TOOLBAR(window->currentbar),
+ GTK_ICON_SIZE_LARGE_TOOLBAR);
+ gtk_box_pack_start(GTK_BOX(window->widgetvbox),
+ window->currentbar, FALSE, FALSE, 0);
+ window->numberh = 0;
+ }
+ gtk_widget_set_size_request(widget, NSGTK_BUTTON_WIDTH,
+ NSGTK_BUTTON_HEIGHT);
+ gtk_toolbar_insert(GTK_TOOLBAR(window->currentbar), GTK_TOOL_ITEM(
+ widget), window->numberh++);
+ gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(widget), TRUE);
+ gtk_drag_source_set(widget, GDK_BUTTON1_MASK, &entry, 1,
+ GDK_ACTION_COPY);
+ gtk_widget_show_all(window->window);
+ return true;
+}
+
+/**
+ * called when a widget is dropped onto the toolbar
+ */
+gboolean nsgtk_toolbar_data(GtkWidget *widget, GdkDragContext *gdc, gint x,
+ gint y, guint time, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ int ind = gtk_toolbar_get_drop_index(nsgtk_scaffolding_toolbar(g),
+ x, y);
+ int q, i;
+ if (window->currentbutton == -1)
+ return TRUE;
+ struct nsgtk_theme *theme =
+ nsgtk_theme_load(GTK_ICON_SIZE_LARGE_TOOLBAR);
+ if (theme == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ return TRUE;
+ }
+ if (nsgtk_scaffolding_button(g, window->currentbutton)->location
+ != -1) {
+ /* widget was already in the toolbar; so replace */
+ if (nsgtk_scaffolding_button(g, window->currentbutton)->
+ location < ind)
+ ind--;
+ gtk_container_remove(GTK_CONTAINER(
+ nsgtk_scaffolding_toolbar(g)), GTK_WIDGET(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button));
+ /* 'move' all widgets further right than the original location,
+ * one place to the left in logical schema */
+ for (i = nsgtk_scaffolding_button(g, window->currentbutton)->
+ location + 1; i < PLACEHOLDER_BUTTON; i++) {
+ q = nsgtk_toolbar_get_id_at_location(g, i);
+ if (q == -1)
+ continue;
+ nsgtk_scaffolding_button(g, q)->location--;
+ }
+ nsgtk_scaffolding_button(g, window->currentbutton)->
+ location = -1;
+ }
+ nsgtk_scaffolding_button(g, window->currentbutton)->button =
+ GTK_TOOL_ITEM(nsgtk_toolbar_make_widget(g,
+ window->currentbutton, theme));
+ free(theme);
+ if (nsgtk_scaffolding_button(g, window->currentbutton)->button
+ == NULL) {
+ warn_user("NoMemory", 0);
+ return TRUE;
+ }
+ /* update logical schema */
+ nsgtk_scaffolding_reset_offset(g);
+ /* 'move' all widgets further right than the new location, one place to
+ * the right in logical schema */
+ for (i = PLACEHOLDER_BUTTON - 1; i >= ind; i--) {
+ q = nsgtk_toolbar_get_id_at_location(g, i);
+ if (q == -1)
+ continue;
+ nsgtk_scaffolding_button(g, q)->location++;
+ }
+ nsgtk_scaffolding_button(g, window->currentbutton)->location = ind;
+
+ /* complete action */
+ gtk_toolbar_insert(nsgtk_scaffolding_toolbar(g),
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button, ind);
+ gtk_tool_item_set_use_drag_window(GTK_TOOL_ITEM(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button), TRUE);
+ gtk_drag_source_set(GTK_WIDGET(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button),
+ GDK_BUTTON1_MASK, &entry, 1, GDK_ACTION_COPY);
+ nsgtk_toolbar_temp_connect(g, window->currentbutton);
+ gtk_widget_show_all(GTK_WIDGET(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button));
+ window->currentbutton = -1;
+ return TRUE;
+}
+
+/**
+ * connected to toolbutton drop; perhaps one day it'll work properly so it may
+ * replace the global current_button
+ */
+
+gboolean nsgtk_toolbar_move_complete(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, GtkSelectionData *selection, guint info,
+ guint time, gpointer data)
+{
+ return FALSE;
+}
+
+/**
+ * called when a widget is dropped onto the store window
+ */
+gboolean nsgtk_toolbar_store_return(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, guint time, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ int q, i;
+
+ if ((window->fromstore) || (window->currentbutton == -1)) {
+ window->currentbutton = -1;
+ return FALSE;
+ }
+ if (nsgtk_scaffolding_button(g, window->currentbutton)->location
+ != -1) {
+ /* 'move' all widgets further right, one place to the left
+ * in logical schema */
+ for (i = nsgtk_scaffolding_button(g, window->currentbutton)->
+ location + 1; i < PLACEHOLDER_BUTTON; i++) {
+ q = nsgtk_toolbar_get_id_at_location(g, i);
+ if (q == -1)
+ continue;
+ nsgtk_scaffolding_button(g, q)->location--;
+ }
+ gtk_container_remove(GTK_CONTAINER(
+ nsgtk_scaffolding_toolbar(g)), GTK_WIDGET(
+ nsgtk_scaffolding_button(g,
+ window->currentbutton)->button));
+ nsgtk_scaffolding_button(g, window->currentbutton)->location
+ = -1;
+ }
+ window->currentbutton = -1;
+ gtk_drag_finish(gdc, TRUE, TRUE, time);
+ return FALSE;
+}
+/**
+ * called when hovering an item above the toolbar
+ */
+gboolean nsgtk_toolbar_action(GtkWidget *widget, GdkDragContext *gdc, gint x,
+ gint y, guint time, gpointer data)
+{
+ nsgtk_scaffolding *g = (nsgtk_scaffolding *)data;
+ GtkToolItem *item = gtk_tool_button_new(NULL, NULL);
+ if (item != NULL)
+ gtk_toolbar_set_drop_highlight_item(
+ nsgtk_scaffolding_toolbar(g),
+ GTK_TOOL_ITEM(item),
+ gtk_toolbar_get_drop_index(
+ nsgtk_scaffolding_toolbar(g), x, y));
+ return FALSE;
+}
+
+/**
+ * called when hovering above the store
+ */
+gboolean nsgtk_toolbar_store_action(GtkWidget *widget, GdkDragContext *gdc,
+ gint x, gint y, guint time, gpointer data)
+{
+ return FALSE;
+}
+/**
+ * called when hovering stops
+ */
+void nsgtk_toolbar_clear(GtkWidget *widget, GdkDragContext *gdc, guint time,
+ gpointer data)
+{
+ gtk_toolbar_set_drop_highlight_item(GTK_TOOLBAR(widget), NULL, 0);
+}
+
+/**
+ * widget factory for creation of toolbar item widgets
+ * \param g the reference scaffolding
+ * \param i the id of the widget
+ * \param theme the theme to make the widgets from
+ */
+GtkWidget *nsgtk_toolbar_make_widget(nsgtk_scaffolding *g,
+ nsgtk_toolbar_button i, struct nsgtk_theme *theme)
+{
+ switch(i) {
+
+/* gtk_tool_button_new() accepts NULL args */
+#define MAKE_STOCKBUTTON(p, q) case p##_BUTTON: {\
+ GtkStockItem item;\
+ char *label = NULL;\
+ gtk_stock_lookup(#q, &item);\
+ if (item.label != NULL)\
+ label = remove_underscores(item.label, false);\
+ GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\
+ theme->image[p##_BUTTON]), label));\
+ if (label != NULL) {\
+ free(label);\
+ label = NULL;\
+ }\
+ return w;\
+ }
+
+ MAKE_STOCKBUTTON(HOME, gtk-home)
+ MAKE_STOCKBUTTON(BACK, gtk-go-back)
+ MAKE_STOCKBUTTON(FORWARD, gtk-go-forward)
+ MAKE_STOCKBUTTON(STOP, gtk-stop)
+ MAKE_STOCKBUTTON(RELOAD, gtk-refresh)
+#undef MAKE_STOCKBUTTON
+ case HISTORY_BUTTON:
+ return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
+ theme->image[HISTORY_BUTTON]), NULL));
+ case URL_BAR_ITEM: {
+ char imagefile[strlen(res_dir_location) + SLEN("html.png")
+ + 1];
+ sprintf(imagefile, "%shtml.png", res_dir_location);
+ GtkWidget *image = GTK_WIDGET(gtk_image_new_from_file(
+ imagefile));
+ GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new());
+ GtkWidget *w = GTK_WIDGET(gtk_tool_item_new());
+ if ((entry == NULL) || (w == NULL)) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+
+ if (image != NULL)
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry),
+ SEXY_ICON_ENTRY_PRIMARY,
+ GTK_IMAGE(image));
+ gtk_container_add(GTK_CONTAINER(w), entry);
+ gtk_tool_item_set_expand(GTK_TOOL_ITEM(w), TRUE);
+ return w;
+ }
+ case THROBBER_ITEM: {
+ if (edit_mode)
+ return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
+ gtk_image_new_from_pixbuf(
+ nsgtk_throbber->framedata[0])),
+ "[throbber]"));
+ if ((nsgtk_throbber == NULL) || (nsgtk_throbber->framedata ==
+ NULL) || (nsgtk_throbber->framedata[0] ==
+ NULL))
+ return NULL;
+ GtkWidget *image = GTK_WIDGET(gtk_image_new_from_pixbuf(
+ nsgtk_throbber->framedata[0]));
+ GtkWidget *w = GTK_WIDGET(gtk_tool_item_new());
+ GtkWidget *al = GTK_WIDGET(gtk_alignment_new(0.1,0.1,0.8,0.8));
+ if ((w == NULL) || (al == NULL)) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+ gtk_alignment_set_padding(GTK_ALIGNMENT(al), 0, 0, 6, 0);
+ if (image != NULL)
+ gtk_container_add(GTK_CONTAINER(al), image);
+ gtk_container_add(GTK_CONTAINER(w), al);
+ return w;
+ }
+ case WEBSEARCH_ITEM: {
+ if (edit_mode)
+ return GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(
+ gtk_image_new_from_stock("gtk-find",
+ GTK_ICON_SIZE_LARGE_TOOLBAR)),
+ "[websearch]"));
+ GtkWidget *image = GTK_WIDGET(gtk_image_new_from_stock(
+ "gtk-info", GTK_ICON_SIZE_LARGE_TOOLBAR));
+ GtkWidget *entry = GTK_WIDGET(sexy_icon_entry_new());
+ GtkWidget *w = GTK_WIDGET(gtk_tool_item_new());
+ if ((entry == NULL) || (w == NULL)) {
+ warn_user(messages_get("NoMemory"), 0);
+ return NULL;
+ }
+
+ gtk_widget_set_size_request(entry, NSGTK_WEBSEARCH_WIDTH,
+ -1);
+ if (image != NULL)
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(entry),
+ SEXY_ICON_ENTRY_PRIMARY,
+ GTK_IMAGE(image));
+ gtk_container_add(GTK_CONTAINER(w), entry);
+ return w;
+ }
+
+/* gtk_tool_button_new accepts NULL args */
+#define MAKE_MENUBUTTON(p, q) case p##_BUTTON: {\
+ char *label = NULL;\
+ label = remove_underscores(messages_get(#q), false);\
+ GtkWidget *w = GTK_WIDGET(gtk_tool_button_new(GTK_WIDGET(\
+ theme->image[p##_BUTTON]), label));\
+ if (label != NULL)\
+ free(label);\
+ return w;\
+ }
+
+ MAKE_MENUBUTTON(NEWWINDOW, gtkNewWindow)
+ MAKE_MENUBUTTON(NEWTAB, gtkNewTab)
+ MAKE_MENUBUTTON(OPENFILE, gtkOpenFile)
+ MAKE_MENUBUTTON(CLOSETAB, gtkCloseTab)
+ MAKE_MENUBUTTON(CLOSEWINDOW, gtkCloseWindow)
+ MAKE_MENUBUTTON(SAVEPAGE, gtkSavePage)
+ MAKE_MENUBUTTON(PRINTPREVIEW, gtkPrintPreview)
+ MAKE_MENUBUTTON(PRINT, gtkPrint)
+ MAKE_MENUBUTTON(QUIT, gtkQuitMenu)
+ MAKE_MENUBUTTON(CUT, gtkCut)
+ MAKE_MENUBUTTON(COPY, gtkCopy)
+ MAKE_MENUBUTTON(PASTE, gtkPaste)
+ MAKE_MENUBUTTON(DELETE, gtkDelete)
+ MAKE_MENUBUTTON(SELECTALL, gtkSelectAll)
+ MAKE_MENUBUTTON(PREFERENCES, gtkPreferences)
+ MAKE_MENUBUTTON(ZOOMPLUS, gtkZoomPlus)
+ MAKE_MENUBUTTON(ZOOMMINUS, gtkZoomMinus)
+ MAKE_MENUBUTTON(ZOOMNORMAL, gtkZoomNormal)
+ MAKE_MENUBUTTON(FULLSCREEN, gtkFullScreen)
+ MAKE_MENUBUTTON(VIEWSOURCE, gtkViewSource)
+ MAKE_MENUBUTTON(CONTENTS, gtkContents)
+ MAKE_MENUBUTTON(ABOUT, gtkAbout)
+ MAKE_MENUBUTTON(PDF, gtkPDF)
+ MAKE_MENUBUTTON(PLAINTEXT, gtkPlainText)
+ MAKE_MENUBUTTON(DRAWFILE, gtkDrawFile)
+ MAKE_MENUBUTTON(POSTSCRIPT, gtkPostScript)
+ MAKE_MENUBUTTON(FIND, gtkFind)
+ MAKE_MENUBUTTON(DOWNLOADS, gtkDownloads)
+ MAKE_MENUBUTTON(SAVEWINDOWSIZE, gtkSaveWindowSize)
+ MAKE_MENUBUTTON(TOGGLEDEBUGGING, gtkToggleDebugging)
+ MAKE_MENUBUTTON(SAVEBOXTREE, gtkSaveBoxTree)
+ MAKE_MENUBUTTON(SAVEDOMTREE, gtkSaveDomTree)
+ MAKE_MENUBUTTON(LOCALHISTORY, gtkLocalHistory)
+ MAKE_MENUBUTTON(GLOBALHISTORY, gtkGlobalHistory)
+ MAKE_MENUBUTTON(ADDBOOKMARKS, gtkAddBookMarks)
+ MAKE_MENUBUTTON(SHOWBOOKMARKS, gtkShowBookMarks)
+ MAKE_MENUBUTTON(OPENLOCATION, gtkOpenLocation)
+ MAKE_MENUBUTTON(NEXTTAB, gtkNextTab)
+ MAKE_MENUBUTTON(PREVTAB, gtkPrevTab)
+ MAKE_MENUBUTTON(GUIDE, gtkGuide)
+ MAKE_MENUBUTTON(INFO, gtkUserInformation)
+ default:
+ return NULL;
+#undef MAKE_MENUBUTTON
+ }
+}
+
+/**
+ * \return toolbar item id when a widget is an element of the scaffolding
+ * else -1
+ */
+int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, nsgtk_scaffolding *g)
+{
+ int i;
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ if ((nsgtk_scaffolding_button(g, i)->location != -1)
+ && (widget == GTK_WIDGET(
+ nsgtk_scaffolding_button(g, i)->button))) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/**
+ * \return toolbar item id from location when there is an item at that logical
+ * location; else -1
+ */
+nsgtk_toolbar_button nsgtk_toolbar_get_id_at_location(nsgtk_scaffolding *g,
+ int i)
+{
+ int q;
+ for (q = BACK_BUTTON; q < PLACEHOLDER_BUTTON; q++)
+ if (nsgtk_scaffolding_button(g, q)->location == i)
+ return q;
+ return -1;
+}
+
+/**
+ * connect 'normal' handlers to toolbar buttons
+ */
+
+void nsgtk_toolbar_connect_all(nsgtk_scaffolding *g)
+{
+ int q, i;
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ q = nsgtk_toolbar_get_id_at_location(g, i);
+ if (q == -1)
+ continue;
+ if (nsgtk_scaffolding_button(g, q)->button != NULL)
+ g_signal_connect(
+ nsgtk_scaffolding_button(g, q)->button,
+ "size-allocate", G_CALLBACK(
+ nsgtk_scaffolding_toolbar_size_allocate
+ ), g);
+ nsgtk_toolbar_set_handler(g, q);
+ }
+}
+
+/**
+ * add handlers to factory widgets
+ * \param g the scaffolding to attach handlers to
+ * \param i the toolbar item id
+ */
+void nsgtk_toolbar_set_handler(nsgtk_scaffolding *g, nsgtk_toolbar_button i)
+{
+ switch(i){
+ case URL_BAR_ITEM:
+ nsgtk_scaffolding_update_url_bar_ref(g);
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)),
+ "activate", G_CALLBACK(
+ nsgtk_window_url_activate_event), g);
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_urlbar(g)),
+ "changed", G_CALLBACK(
+ nsgtk_window_url_changed), g);
+ break;
+ case THROBBER_ITEM:
+ nsgtk_scaffolding_update_throbber_ref(g);
+ break;
+ case WEBSEARCH_ITEM:
+ nsgtk_scaffolding_update_websearch_ref(g);
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)),
+ "activate", G_CALLBACK(
+ nsgtk_websearch_activate), g);
+ g_signal_connect(GTK_WIDGET(nsgtk_scaffolding_websearch(g)),
+ "button-press-event", G_CALLBACK(
+ nsgtk_websearch_clear), g);
+ break;
+ default:
+ if ((nsgtk_scaffolding_button(g, i)->bhandler != NULL) &&
+ (nsgtk_scaffolding_button(g, i)->button
+ != NULL))
+ g_signal_connect(nsgtk_scaffolding_button(g, i)->
+ button, "clicked",
+ G_CALLBACK(nsgtk_scaffolding_button(g,
+ i)->bhandler), g);
+ break;
+ }
+}
+
+#define DATAHANDLER(p, q, r)\
+gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\
+ *cont, GtkSelectionData *selection, guint info, guint time,\
+ gpointer data)\
+{\
+ r->currentbutton = q##_BUTTON;\
+ r->fromstore = true;\
+ return TRUE;\
+}\
+gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\
+ GdkDragContext *cont, GtkSelectionData *selection, guint info,\
+ guint time, gpointer data)\
+{\
+ r->currentbutton = q##_BUTTON;\
+ r->fromstore = false;\
+ return TRUE;\
+}
+
+DATAHANDLER(home, HOME, window)
+DATAHANDLER(forward, FORWARD, window)
+DATAHANDLER(back, BACK, window)
+DATAHANDLER(stop, STOP, window)
+DATAHANDLER(reload, RELOAD, window)
+DATAHANDLER(history, HISTORY, window)
+DATAHANDLER(newwindow, NEWWINDOW, window)
+DATAHANDLER(newtab, NEWTAB, window)
+DATAHANDLER(openfile, OPENFILE, window)
+DATAHANDLER(closetab, CLOSETAB, window)
+DATAHANDLER(closewindow, CLOSEWINDOW, window)
+DATAHANDLER(savepage, SAVEPAGE, window)
+DATAHANDLER(printpreview, PRINTPREVIEW, window)
+DATAHANDLER(print, PRINT, window)
+DATAHANDLER(quit, QUIT, window)
+DATAHANDLER(cut, CUT, window)
+DATAHANDLER(copy, COPY, window)
+DATAHANDLER(paste, PASTE, window)
+DATAHANDLER(delete, DELETE, window)
+DATAHANDLER(selectall, SELECTALL, window)
+DATAHANDLER(preferences, PREFERENCES, window)
+DATAHANDLER(zoomplus, ZOOMPLUS, window)
+DATAHANDLER(zoomminus, ZOOMMINUS, window)
+DATAHANDLER(zoomnormal, ZOOMNORMAL, window)
+DATAHANDLER(fullscreen, FULLSCREEN, window)
+DATAHANDLER(viewsource, VIEWSOURCE, window)
+DATAHANDLER(contents, CONTENTS, window)
+DATAHANDLER(about, ABOUT, window)
+DATAHANDLER(pdf, PDF, window)
+DATAHANDLER(plaintext, PLAINTEXT, window)
+DATAHANDLER(drawfile, DRAWFILE, window)
+DATAHANDLER(postscript, POSTSCRIPT, window)
+DATAHANDLER(find, FIND, window)
+DATAHANDLER(downloads, DOWNLOADS, window)
+DATAHANDLER(savewindowsize, SAVEWINDOWSIZE, window)
+DATAHANDLER(toggledebugging, TOGGLEDEBUGGING, window)
+DATAHANDLER(saveboxtree, SAVEBOXTREE, window)
+DATAHANDLER(savedomtree, SAVEDOMTREE, window)
+DATAHANDLER(localhistory, LOCALHISTORY, window)
+DATAHANDLER(globalhistory, GLOBALHISTORY, window)
+DATAHANDLER(addbookmarks, ADDBOOKMARKS, window)
+DATAHANDLER(showbookmarks, SHOWBOOKMARKS, window)
+DATAHANDLER(openlocation, OPENLOCATION, window)
+DATAHANDLER(nexttab, NEXTTAB, window)
+DATAHANDLER(prevtab, PREVTAB, window)
+DATAHANDLER(guide, GUIDE, window)
+DATAHANDLER(info, INFO, window)
+#undef DATAHANDLER
+#define DATAHANDLER(p, q, r)\
+gboolean nsgtk_toolbar_##p##_button_data(GtkWidget *widget, GdkDragContext\
+ *cont, GtkSelectionData *selection, guint info, guint time,\
+ gpointer data)\
+{\
+ r->currentbutton = q##_ITEM;\
+ r->fromstore = true;\
+ return TRUE;\
+}\
+gboolean nsgtk_toolbar_##p##_toolbar_button_data(GtkWidget *widget,\
+ GdkDragContext *cont, GtkSelectionData *selection, guint info,\
+ guint time, gpointer data)\
+{\
+ r->currentbutton = q##_ITEM;\
+ r->fromstore = false;\
+ return TRUE;\
+}
+
+DATAHANDLER(throbber, THROBBER, window)
+DATAHANDLER(websearch, WEBSEARCH, window)
+#undef DATAHANDLER
+
+/**
+ * connect temporary handler for toolbar edit events
+ */
+void nsgtk_toolbar_temp_connect(nsgtk_scaffolding *g, nsgtk_toolbar_button i)
+{
+ if ((i == URL_BAR_ITEM) ||
+ (nsgtk_scaffolding_button(g, i)->button == NULL) ||
+ (nsgtk_scaffolding_button(g, i)->dataminus == NULL))
+ return;
+ g_signal_connect(nsgtk_scaffolding_button(g, i)->button,
+ "drag-data-get", G_CALLBACK(nsgtk_scaffolding_button(
+ g, i)->dataminus), g);
+}
+
+/**
+ * load toolbar settings from file; file is a set of fields arranged as
+ * <itemreference>;<itemlocation>|<itemreference>;<itemlocation>| etc
+ */
+void nsgtk_toolbar_customization_load(nsgtk_scaffolding *g)
+{
+ int i, ii;
+ char *val;
+ char buffer[SLEN("11;|") * 2 * PLACEHOLDER_BUTTON]; /* numbers 0-99 */
+ buffer[0] = '\0';
+ char *buffer1, *subbuffer, *ptr = NULL, *pter = NULL;
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
+ nsgtk_scaffolding_button(g, i)->location =
+ (i <= THROBBER_ITEM) ? i : -1;
+ FILE *f = fopen(toolbar_indices_file_location, "r");
+ if (f == NULL) {
+ warn_user(messages_get("gtkFileError"),
+ toolbar_indices_file_location);
+ return;
+ }
+ val = fgets(buffer, sizeof buffer, f);
+ if (val == NULL)
+ LOG(("empty read toolbar settings"));
+ fclose(f);
+ i = BACK_BUTTON;
+ ii = BACK_BUTTON;
+ buffer1 = strtok_r(buffer, "|", &ptr);
+ while (buffer1 != NULL) {
+ subbuffer = strtok_r(buffer1, ";", &pter);
+ i = atoi(subbuffer);
+ subbuffer = strtok_r(NULL, ";", &pter);
+ ii = atoi(subbuffer);
+ if ((i >= BACK_BUTTON) && (i < PLACEHOLDER_BUTTON) &&
+ (ii >= -1) && (ii < PLACEHOLDER_BUTTON)) {
+ nsgtk_scaffolding_button(g, i)->location = ii;
+ }
+ buffer1 = strtok_r(NULL, "|", &ptr);
+ }
+}
+
+/**
+ * cast toolbar settings to all scaffoldings referenced from the global linked
+ * list of gui_windows
+ */
+void nsgtk_toolbar_cast(nsgtk_scaffolding *g)
+{
+ int i;
+ nsgtk_scaffolding *list = scaf_list;
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
+ window->buttonlocations[i] =
+ ((nsgtk_scaffolding_button(g, i)->location
+ >= -1) &&
+ (nsgtk_scaffolding_button(g, i)->location
+ < PLACEHOLDER_BUTTON)) ?
+ nsgtk_scaffolding_button(g, i)->location : -1;
+ while (list) {
+ if (list != g)
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++)
+ nsgtk_scaffolding_button(list, i)->location =
+ window->buttonlocations[i];
+ list = nsgtk_scaffolding_iterate(list);
+ }
+}
+
+/**
+ * save toolbar settings to file
+ */
+void nsgtk_toolbar_customization_save(nsgtk_scaffolding *g)
+{
+ int i;
+ FILE *f = fopen(toolbar_indices_file_location, "w");
+ if (f == NULL){
+ warn_user("gtkFileError", toolbar_indices_file_location);
+ return;
+ }
+ for (i = BACK_BUTTON; i < PLACEHOLDER_BUTTON; i++) {
+ fprintf(f, "%d;%d|", i, nsgtk_scaffolding_button(g, i)->location);
+ }
+ fclose(f);
+}
+
diff --git a/gtk/gtk_toolbar.h b/gtk/gtk_toolbar.h
new file mode 100644
index 000000000..a470a4480
--- /dev/null
+++ b/gtk/gtk_toolbar.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _NETSURF_GTK_TOOLBAR_H_
+#define _NETSURF_GTK_TOOLBAR_H_
+
+#include <gtk/gtk.h>
+#include "gtk/gtk_scaffolding.h"
+
+void nsgtk_toolbar_customization_init(nsgtk_scaffolding *g);
+void nsgtk_toolbar_init(nsgtk_scaffolding *g);
+void nsgtk_toolbar_customization_load(nsgtk_scaffolding *g);
+void nsgtk_toolbar_set_physical(nsgtk_scaffolding *g);
+void nsgtk_toolbar_connect_all(nsgtk_scaffolding *g);
+int nsgtk_toolbar_get_id_from_widget(GtkWidget *widget, nsgtk_scaffolding
+ *g);
+
+#define TOOLPROTO(q) gboolean nsgtk_toolbar_##q##_button_data(\
+ GtkWidget *widget, GdkDragContext *cont, GtkSelectionData\
+ *selection, guint info, guint time, gpointer data);\
+gboolean nsgtk_toolbar_##q##_toolbar_button_data(GtkWidget *widget,\
+ GdkDragContext *cont, GtkSelectionData *selection, guint info,\
+ guint time, gpointer data)
+TOOLPROTO(home);
+TOOLPROTO(back);
+TOOLPROTO(forward);
+TOOLPROTO(reload);
+TOOLPROTO(stop);
+TOOLPROTO(throbber);
+TOOLPROTO(websearch);
+TOOLPROTO(history);
+TOOLPROTO(newwindow);
+TOOLPROTO(newtab);
+TOOLPROTO(openfile);
+TOOLPROTO(closetab);
+TOOLPROTO(closewindow);
+TOOLPROTO(savepage);
+TOOLPROTO(pdf);
+TOOLPROTO(plaintext);
+TOOLPROTO(drawfile);
+TOOLPROTO(postscript);
+TOOLPROTO(printpreview);
+TOOLPROTO(print);
+TOOLPROTO(quit);
+TOOLPROTO(cut);
+TOOLPROTO(copy);
+TOOLPROTO(paste);
+TOOLPROTO(delete);
+TOOLPROTO(selectall);
+TOOLPROTO(find);
+TOOLPROTO(preferences);
+TOOLPROTO(zoomplus);
+TOOLPROTO(zoomminus);
+TOOLPROTO(zoomnormal);
+TOOLPROTO(fullscreen);
+TOOLPROTO(viewsource);
+TOOLPROTO(downloads);
+TOOLPROTO(localhistory);
+TOOLPROTO(globalhistory);
+TOOLPROTO(addbookmarks);
+TOOLPROTO(showbookmarks);
+TOOLPROTO(openlocation);
+TOOLPROTO(nexttab);
+TOOLPROTO(prevtab);
+TOOLPROTO(savewindowsize);
+TOOLPROTO(toggledebugging);
+TOOLPROTO(saveboxtree);
+TOOLPROTO(savedomtree);
+TOOLPROTO(contents);
+TOOLPROTO(guide);
+TOOLPROTO(info);
+TOOLPROTO(about);
+#undef TOOLPROTO
+
+#endif
diff --git a/gtk/gtk_window.c b/gtk/gtk_window.c
index aa0ccaae6..54e9c16a1 100644
--- a/gtk/gtk_window.c
+++ b/gtk/gtk_window.c
@@ -22,6 +22,7 @@
#include "gtk/gtk_window.h"
#include "desktop/browser.h"
#include "desktop/options.h"
+#include "desktop/searchweb.h"
#include "desktop/textinput.h"
#include "desktop/selection.h"
#include "gtk/gtk_gui.h"
@@ -35,7 +36,36 @@
#include <gdk/gdkkeysyms.h>
#include <assert.h>
-struct gui_window *window_list = 0; /**< first entry in win list*/
+struct gui_window {
+ /* All gui_window objects have an ultimate scaffold */
+ nsgtk_scaffolding *scaffold;
+ /**< the gtk object containing menu, buttons, url bar, [tabs],
+ * drawing area, etc that may contain 1 -> several gui_windows */
+ struct browser_window *bw;
+ /**< the 'content' window that is rendered in the gui_window*/
+ struct browser_mouse *mouse; /**< contains mouse state / events */
+
+ int caretx, carety, careth;
+ /**< storage caret dimension / location for rendering */
+ gui_pointer_shape current_pointer;
+ /**< storage caret shape for rendering */
+ int last_x, last_y;
+ /**< storage caret location for rendering */
+
+ GtkScrolledWindow *scrolledwindow;
+ /**< optional; for frames that need it; top level of gtk structure of
+ * gui_window */
+ GtkViewport *viewport;
+ /**< contained in a scrolled window */
+ GtkFixed *fixed; /**< contained in a viewport */
+ GtkDrawingArea *drawing_area; /**< contained in a gtkfixed */
+ GtkWidget *tab; /** the visible tab */
+ gulong signalhandler[NSGTK_WINDOW_SIGNAL_COUNT];
+ /**< to allow disactivation / resume of normal window behaviour */
+ struct gui_window *next, *prev; /**< list for eventual cleanup */
+};
+
+struct gui_window *window_list = NULL; /**< first entry in win list*/
int temp_open_background = -1;
@@ -60,19 +90,45 @@ static void nsgtk_redraw_caret(struct gui_window *g);
static GdkCursor *nsgtk_create_menu_cursor(void);
-struct browser_window *nsgtk_get_browser_window(struct gui_window *g)
+nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g)
+{
+ return g->scaffold;
+}
+
+struct browser_window *gui_window_get_browser_window(struct gui_window *g)
{
return g->bw;
}
-nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g)
+unsigned long nsgtk_window_get_signalhandler(struct gui_window *g, int i)
{
- return g->scaffold;
+ return g->signalhandler[i];
}
-struct browser_window *nsgtk_get_browser_for_gui(struct gui_window *g)
+GtkDrawingArea *nsgtk_window_get_drawing_area(struct gui_window *g)
{
- return g->bw;
+ return g->drawing_area;
+}
+
+GtkScrolledWindow *nsgtk_window_get_scrolledwindow(struct gui_window *g)
+{
+ return g->scrolledwindow;
+}
+
+GtkWidget *nsgtk_window_get_tab(struct gui_window *g)
+{
+ return g->tab;
+}
+
+void nsgtk_window_set_tab(struct gui_window *g, GtkWidget *w)
+{
+ g->tab = w;
+}
+
+
+struct gui_window *nsgtk_window_iterate(struct gui_window *g)
+{
+ return g->next;
}
float nsgtk_get_scale_for_gui(struct gui_window *g)
@@ -111,13 +167,6 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
g->careth = 0;
- /* Attach ourselves to the list (push_top) */
- if (window_list)
- window_list->prev = g;
- g->next = window_list;
- g->prev = NULL;
- window_list = g;
-
if (bw->parent != NULL)
/* Find our parent's scaffolding */
g->scaffold = bw->parent->window->scaffold;
@@ -127,9 +176,20 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
else
/* Now construct and attach a scaffold */
g->scaffold = nsgtk_new_scaffolding(g);
+ if (g->scaffold == NULL) {
+ free(g);
+ return NULL;
+ }
- /* Construct our primary elements */
- g->fixed = GTK_FIXED(gtk_fixed_new());
+ /* Attach ourselves to the list (push_top) */
+ if (window_list)
+ window_list->prev = g;
+ g->next = window_list;
+ g->prev = NULL;
+ window_list = g;
+
+ /* Construct our primary elements */
+ g->fixed = GTK_FIXED(gtk_fixed_new());
g->drawing_area = GTK_DRAWING_AREA(gtk_drawing_area_new());
gtk_fixed_put(g->fixed, GTK_WIDGET(g->drawing_area), 0, 0);
gtk_container_set_border_width(GTK_CONTAINER(g->fixed), 0);
@@ -219,6 +279,7 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK |
+ GDK_POINTER_MOTION_HINT_MASK |
GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK);
GTK_WIDGET_SET_FLAGS(GTK_WIDGET(g->drawing_area), GTK_CAN_FOCUS);
@@ -229,17 +290,20 @@ struct gui_window *gui_create_browser_window(struct browser_window *bw,
#define CONNECT(obj, sig, callback, ptr) \
g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr))
- CONNECT(g->drawing_area, "expose_event", nsgtk_window_expose_event, g);
+ g->signalhandler[NSGTK_WINDOW_SIGNAL_REDRAW] =
+ CONNECT(g->drawing_area, "expose_event",
+ nsgtk_window_expose_event, g);
CONNECT(g->drawing_area, "motion_notify_event",
- nsgtk_window_motion_notify_event, g);
- CONNECT(g->drawing_area, "button_press_event",
- nsgtk_window_button_press_event, g);
+ nsgtk_window_motion_notify_event, g);
+ g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] =
+ CONNECT(g->drawing_area, "button_press_event",
+ nsgtk_window_button_press_event, g);
CONNECT(g->drawing_area, "button_release_event",
- nsgtk_window_button_release_event, g);
+ nsgtk_window_button_release_event, g);
CONNECT(g->drawing_area, "key_press_event",
- nsgtk_window_keypress_event, g);
+ nsgtk_window_keypress_event, g);
CONNECT(g->viewport, "size_allocate",
- nsgtk_window_size_allocate_event, g);
+ nsgtk_window_size_allocate_event, g);
return g;
}
@@ -344,7 +408,9 @@ gboolean nsgtk_window_motion_notify_event(GtkWidget *widget,
struct gui_window *g = data;
bool shift = event->state & GDK_SHIFT_MASK;
bool ctrl = event->state & GDK_CONTROL_MASK;
-
+ if ((abs(event->x - g->last_x) < 5) && (abs(event->y - g->last_y) < 5))
+ /* necessary for touch screens */
+ return FALSE;
if (g->mouse->state & BROWSER_MOUSE_PRESS_1){
/* Start button 1 drag */
browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_1,
@@ -384,29 +450,24 @@ gboolean nsgtk_window_button_press_event(GtkWidget *widget,
struct gui_window *g = data;
gtk_widget_grab_focus(GTK_WIDGET(g->drawing_area));
+ gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window(
+ g->scaffold)->window));
g->mouse->pressed_x = event->x / g->bw->scale;
g->mouse->pressed_y = event->y / g->bw->scale;
- if (event->button == 3) {
- /** \todo
- * Firstly, MOUSE_PRESS_2 on GTK is a middle click, which doesn't
- * appear correct to me. Secondly, right-clicks are not passed to
- * browser_window_mouse_click() at all, which also seems incorrect
- * since they should result in browser_window_remove_caret().
- *
- * I would surmise we need a MOUSE_PRESS_3, unless right-clicking is
- * supposed to be mapped to MOUSE_PRESS_2, but that doesn't appear
- * correct either.
- */
- browser_window_remove_caret(g->bw);
- nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse->pressed_x, g->mouse->pressed_y);
- return TRUE;
- }
-
switch (event->button) {
- case 1: g->mouse->state = BROWSER_MOUSE_PRESS_1; break;
- case 2: g->mouse->state = BROWSER_MOUSE_PRESS_2; break;
+ case 1:
+ g->mouse->state = BROWSER_MOUSE_PRESS_1;
+ break;
+ case 3:
+ browser_window_remove_caret(g->bw);
+ nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse->pressed_x,
+ g->mouse->pressed_y);
+ g->mouse->state = BROWSER_MOUSE_PRESS_2;
+ break;
+ default:
+ return FALSE;
}
/* Handle the modifiers too */
if (event->state & GDK_SHIFT_MASK)
@@ -565,7 +626,7 @@ void nsgtk_reflow_all_windows(void)
{
for (struct gui_window *g = window_list; g; g = g->next) {
nsgtk_tab_options_changed(GTK_WIDGET(
- nsgtk_scaffolding_get_notebook(g)));
+ nsgtk_scaffolding_notebook(g->scaffold)));
g->bw->reformat_pending = true;
}
@@ -702,6 +763,12 @@ void gui_window_set_scroll(struct gui_window *g, int sx, int sy)
gtk_adjustment_set_value(hadj, x);
}
+void gui_window_scroll_visible(struct gui_window *g, int x0, int y0,
+ int x1, int y1)
+{
+ gui_window_set_scroll(g,x0,y0);
+}
+
/**
* Set the scale setting of a window
diff --git a/gtk/gtk_window.h b/gtk/gtk_window.h
index 71c86bca5..58754bdda 100644
--- a/gtk/gtk_window.h
+++ b/gtk/gtk_window.h
@@ -23,36 +23,6 @@
#include "desktop/browser.h"
#include "gtk/gtk_scaffolding.h"
-struct gui_window {
- /* All gui_window objects have an ultimate scaffold */
- nsgtk_scaffolding *scaffold;
- /* A gui_window is the rendering of a browser_window */
- struct browser_window *bw;
- struct browser_mouse *mouse;
-
- /* These are the storage for the rendering */
- int caretx, carety, careth;
- gui_pointer_shape current_pointer;
- int last_x, last_y;
-
- /* Within GTK, a gui_window is a scrolled window
- * with a viewport inside
- * with a gtkfixed in that
- * with a drawing area in that
- * The scrolled window is optional and only chosen
- * for frames which need it. Otherwise we just use
- * a viewport.
- */
- GtkWidget *tab;
- GtkScrolledWindow *scrolledwindow;
- GtkViewport *viewport;
- GtkFixed *fixed;
- GtkDrawingArea *drawing_area;
-
- /* Keep gui_windows in a list for cleanup later */
- struct gui_window *next, *prev;
-};
-
struct browser_mouse {
struct gui_window *gui;
struct box *box;
@@ -63,19 +33,29 @@ struct browser_mouse {
browser_mouse_state state;
};
-extern struct gui_window * window_list;
+typedef enum nsgtk_window_signals {
+ NSGTK_WINDOW_SIGNAL_CLICK,
+ NSGTK_WINDOW_SIGNAL_REDRAW,
+ NSGTK_WINDOW_SIGNAL_COUNT
+} nsgtk_window_signal;
+
+extern struct gui_window *window_list;
extern int temp_open_background;
void nsgtk_reflow_all_windows(void);
void nsgtk_window_process_reformats(void);
nsgtk_scaffolding *nsgtk_get_scaffold(struct gui_window *g);
-struct browser_window *nsgtk_get_browser_for_gui(struct gui_window *g);
float nsgtk_get_scale_for_gui(struct gui_window *g);
int nsgtk_gui_window_update_targets(struct gui_window *g);
void nsgtk_window_destroy_browser(struct gui_window *g);
+unsigned long nsgtk_window_get_signalhandler(struct gui_window *g, int i);
+GtkDrawingArea *nsgtk_window_get_drawing_area(struct gui_window *g);
+struct gui_window *nsgtk_window_iterate(struct gui_window *g);
+GtkScrolledWindow *nsgtk_window_get_scrolledwindow(struct gui_window *g);
+GtkWidget *nsgtk_window_get_tab(struct gui_window *g);
+void nsgtk_window_set_tab(struct gui_window *g, GtkWidget *w);
-struct browser_window *nsgtk_get_browser_window(struct gui_window *g);
#endif /* NETSURF_GTK_WINDOW_H */
diff --git a/gtk/options.h b/gtk/options.h
index ec48c326d..c2f5e48e8 100644
--- a/gtk/options.h
+++ b/gtk/options.h
@@ -34,6 +34,8 @@ extern int option_history_age;
extern bool option_hover_urls;
extern bool option_focus_new;
extern bool option_new_blank;
+extern bool option_source_tab;
+extern int option_current_theme;
#define EXTRA_OPTION_DEFINE \
bool option_render_resample = false; \
@@ -48,7 +50,9 @@ bool option_disable_plugins = false; \
int option_history_age = 0; \
bool option_hover_urls = false; \
bool option_focus_new = false; \
-bool option_new_blank = false;
+bool option_new_blank = false; \
+bool option_source_tab = false;\
+int option_current_theme = 0;
#define EXTRA_OPTION_TABLE \
{ "render_resample", OPTION_BOOL, &option_render_resample }, \
@@ -63,6 +67,8 @@ bool option_new_blank = false;
{ "history_age", OPTION_INTEGER, &option_history_age}, \
{ "hover_urls", OPTION_BOOL, &option_hover_urls}, \
{ "focus_new", OPTION_BOOL, &option_focus_new}, \
-{ "new_blank", OPTION_BOOL, &option_new_blank}
+{ "new_blank", OPTION_BOOL, &option_new_blank}, \
+{ "source_tab", OPTION_BOOL, &option_source_tab},\
+{ "current_theme", OPTION_INTEGER, &option_current_theme}
#endif
diff --git a/gtk/res/SearchEngines b/gtk/res/SearchEngines
new file mode 100644
index 000000000..e9eb466c2
--- /dev/null
+++ b/gtk/res/SearchEngines
@@ -0,0 +1,20 @@
+Google|www.google.com|http://www.google.com/search?q=%s|http://www.google.com/favicon.ico|
+Yahoo|search.yahoo.com|http://search.yahoo.com/search?p=%s|http://www.yahoo.com/favicon.ico|
+Bing|www.bing.com|http://www.bing.com/search?q=%s|http://www.bing.com/favicon.ico|
+Business.com|www.business.com|http://www.business.com/search/rslt_default.asp?query=%s|http://www.business.com/favicon.ico|
+Omgili|www.omgili.com|http://www.omgili.com/AAAAA/%s.html|http://www.omgili.com/favicon.ico|
+BBC News|search.bbc.co.uk|http://search.bbc.co.uk/search?q=%s&tab=ns|http://news.bbc.co.uk/favicon.ico|
+Ubuntu Packages|packages.ubuntu.com|http://packages.ubuntu.com/search?keywords=%s|http://packages.ubuntu.com/favicon.ico|
+Creative Commons|creativecommons.org|http://creativecommons.org/?s=%s|http://creativecommons.org/favicon.ico|
+Ask.com|www.ask.com|http://www.ask.com/web?q=%s|http://www.ask.com/favicon.ico|
+Answers.com|www.answers.com|http://www.answers.com/%s|http://www.answers.com/favicon.ico|
+Dictionary.com|dictionary.reference.com|http://dictionary.reference.com/browse/%s?jss=0|http://dictionary.reference.com/favicon.ico|
+Youtube|www.youtube.com|http://www.youtube.com/results?search_query=%s|http://www.youtube.com/favicon.ico|
+AeroMp3|www.aeromp3.com|http://www.aeromp3.com/search?q=%s|http://www.aeromp3.com/favicon.ico|
+AOL|search.aol.com|http://search.aol.com/aol/search?query=%s|http://www.aol.com/favicon.ico|
+Baidu|www.baidu.com|http://www.baidu.com/s?wd=%s|http://www.baidu.com/favicon.ico|
+Amazon|www.amazon.com|http://www.amazon.com/s/ref=nb_ss_gw?field-keywords=%s|http://www.amazon.com/favicon.ico|
+Ebay|shop.ebay.com|http://shop.ebay.com/items/%s|http://www.ebay.com/favicon.ico|
+IMDB|www.imdb.com|http://www.imdb.com/find?q=%s|http://www.imdb.com/favicon.ico|
+ESPN|search.espn.go.com|http://search.espn.go.com/%s/|http://www.espn.go.com/favicon.ico|
+Wikipedia|en.wikipedia.org|http://en.wikipedia.org/w/index.php?title=Special%%3ASearch&search=%s|http://en.wikipedia.org/favicon.ico|
diff --git a/gtk/res/default.ico b/gtk/res/default.ico
new file mode 100644
index 000000000..1cb432828
--- /dev/null
+++ b/gtk/res/default.ico
Binary files differ
diff --git a/gtk/res/html.png b/gtk/res/html.png
new file mode 100644
index 000000000..d44dcadce
--- /dev/null
+++ b/gtk/res/html.png
Binary files differ
diff --git a/gtk/res/login.glade b/gtk/res/login.glade
new file mode 100644
index 000000000..c46740591
--- /dev/null
+++ b/gtk/res/login.glade
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkDialog" id="wndLogin">
+ <property name="title" translatable="yes">Site Authentication</property>
+ <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox12">
+ <property name="visible">True</property>
+ <property name="border_width">3</property>
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="yalign">0.10000000149011612</property>
+ <property name="xpad">12</property>
+ <property name="icon_size">6</property>
+ <property name="icon_name">gtk-dialog-authentication</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkTable" id="table5">
+ <property name="visible">True</property>
+ <property name="border_width">1</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="column_spacing">11</property>
+ <property name="row_spacing">10</property>
+ <child>
+ <widget class="GtkLabel" id="labelLoginHost">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">moo.yoo.com</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label57">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password</property>
+ </widget>
+ <packing>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label56">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Username</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label54">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Host</property>
+ </widget>
+ <packing>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label55">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Realm</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="labelLoginRealm">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">my sekr3t area</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entryLoginPass">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="activates_default">True</property>
+ <property name="text" translatable="yes">opensesame</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entryLoginUser">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="text" translatable="yes">sesame</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="buttonLoginCan">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="buttonLoginOK">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="response_id">-5</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkImage" id="image2">
+ <property name="visible">True</property>
+ <property name="stock">gtk-ok</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label49">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Login</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gtk/res/netsurf.glade b/gtk/res/netsurf.glade
index 13d5e716c..3fef4315d 100644
--- a/gtk/res/netsurf.glade
+++ b/gtk/res/netsurf.glade
@@ -12,197 +12,10 @@
<widget class="GtkMenuBar" id="menubar">
<property name="visible">True</property>
<child>
- <widget class="GtkMenuItem" id="menuitem_main">
+ <widget class="GtkMenuItem" id="menuitem_file">
<property name="visible">True</property>
<property name="label" translatable="yes">_File</property>
<property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="menuitem_main_menu">
- <child>
- <widget class="GtkImageMenuItem" id="new_window">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Opens a new browser window.</property>
- <property name="label" translatable="yes">_New Window</property>
- <property name="use_underline">True</property>
- <accelerator key="n" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image608">
- <property name="visible">True</property>
- <property name="stock">gtk-new</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="new_tab">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Opens a new browser tab.</property>
- <property name="label" translatable="yes">New _Tab</property>
- <property name="use_underline">True</property>
- <accelerator key="t" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image609">
- <property name="visible">True</property>
- <property name="stock">gtk-new</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="open_file">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Open a file on your computer into this browser window.</property>
- <property name="label" translatable="yes">_Open File...</property>
- <property name="use_underline">True</property>
- <accelerator key="o" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image610">
- <property name="visible">True</property>
- <property name="stock">gtk-open</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="close_window">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Close this browser window.</property>
- <property name="label" translatable="yes">_Close Window</property>
- <property name="use_underline">True</property>
- <accelerator key="w" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image611">
- <property name="visible">True</property>
- <property name="stock">gtk-close</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separatormenuitem1">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="save_page">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Save this page to disc, optionally including images, etc.</property>
- <property name="label" translatable="yes">Save page...</property>
- <property name="use_underline">True</property>
- <child internal-child="image">
- <widget class="GtkImage" id="image612">
- <property name="visible">True</property>
- <property name="stock">gtk-save-as</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="export">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Export the page to a different format.</property>
- <property name="label" translatable="yes">Export</property>
- <property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="export_menu">
- <child>
- <widget class="GtkMenuItem" id="export_plain_text">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Plain ASCII text, readable in text editors and views.</property>
- <property name="label" translatable="yes">Plain text...</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="export_drawfile">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">RISC OS Drawfile vector graphic.</property>
- <property name="label" translatable="yes">Drawfile...</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="export_postscript">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">PostScript for printing and converting to PDFs.</property>
- <property name="label" translatable="yes">PostScript...</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="export_pdf">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Portable Document Format.</property>
- <property name="label" translatable="yes">PDF...</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator2">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="print_preview">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Show how a print out might look like.</property>
- <property name="label" translatable="yes">Print preview...</property>
- <property name="use_underline">True</property>
- <accelerator key="P" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image613">
- <property name="visible">True</property>
- <property name="stock">gtk-print-preview</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="print">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Produce a hardcopy on your printer.</property>
- <property name="label" translatable="yes">Print...</property>
- <property name="use_underline">True</property>
- <accelerator key="P" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image614">
- <property name="visible">True</property>
- <property name="stock">gtk-print</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator3">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="quit">
- <property name="visible">True</property>
- <property name="label">gtk-quit</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
<child>
@@ -210,93 +23,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">_Edit</property>
<property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="menuitem_edit_menu">
- <child>
- <widget class="GtkImageMenuItem" id="cut">
- <property name="visible">True</property>
- <property name="label">gtk-cut</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="copy">
- <property name="visible">True</property>
- <property name="label">gtk-copy</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="paste">
- <property name="visible">True</property>
- <property name="label">gtk-paste</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="delete">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="label">gtk-delete</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator4">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="select_all">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Selects all text in the current browser window.</property>
- <property name="label">gtk-select-all</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- <accelerator key="a" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator5">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="find">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Find specific text in the current browser window.</property>
- <property name="label" translatable="yes">_Find...</property>
- <property name="use_underline">True</property>
- <accelerator key="F" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator6">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="preferences">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Change how NetSurf functions.</property>
- <property name="label" translatable="yes">P_references...</property>
- <property name="use_underline">True</property>
- <child internal-child="image">
- <widget class="GtkImage" id="image615">
- <property name="visible">True</property>
- <property name="stock">gtk-preferences</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
<child>
@@ -304,375 +30,13 @@
<property name="visible">True</property>
<property name="label" translatable="yes">_View</property>
<property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="menuitem_view_menu">
- <child>
- <widget class="GtkImageMenuItem" id="stop">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Stop</property>
- <property name="use_underline">True</property>
- <accelerator key="Escape" modifiers="" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image616">
- <property name="visible">True</property>
- <property name="stock">gtk-stop</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="reload">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Reload</property>
- <property name="use_underline">True</property>
- <accelerator key="F5" modifiers="" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image617">
- <property name="visible">True</property>
- <property name="stock">gtk-refresh</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator10">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="scale_view">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Scale the page in the current browser window to be smaller or larger.</property>
- <property name="label" translatable="yes">_Scale View...</property>
- <property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="scale_view_menu">
- <child>
- <widget class="GtkImageMenuItem" id="zoom_in">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Zoom _in</property>
- <property name="use_underline">True</property>
- <child internal-child="image">
- <widget class="GtkImage" id="image619">
- <property name="visible">True</property>
- <property name="stock">gtk-zoom-in</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="normal_size">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Normal size</property>
- <property name="use_underline">True</property>
- <child internal-child="image">
- <widget class="GtkImage" id="image620">
- <property name="visible">True</property>
- <property name="stock">gtk-zoom-100</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="zoom_out">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Zoom _out</property>
- <property name="use_underline">True</property>
- <child internal-child="image">
- <widget class="GtkImage" id="image621">
- <property name="visible">True</property>
- <property name="stock">gtk-zoom-out</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- <child internal-child="image">
- <widget class="GtkImage" id="image618">
- <property name="visible">True</property>
- <property name="stock">gtk-zoom-in</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="full_screen">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Fullscreen</property>
- <property name="use_underline">True</property>
- <accelerator key="F11" modifiers="" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image622">
- <property name="visible">True</property>
- <property name="stock">gtk-fullscreen</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="view_source">
- <property name="visible">True</property>
- <property name="label" translatable="yes">View S_ource</property>
- <property name="use_underline">True</property>
- <child internal-child="image">
- <widget class="GtkImage" id="menu-item-image28">
- <property name="visible">True</property>
- <property name="stock">gtk-index</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator12">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="images">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="label" translatable="yes">_Images...</property>
- <property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="images_menu">
- <child>
- <widget class="GtkCheckMenuItem" id="foreground_images">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Toggle the display of images in the foreground.</property>
- <property name="label" translatable="yes">_Foreground Images</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkCheckMenuItem" id="background_images">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Toggle the display of images in the background.</property>
- <property name="label" translatable="yes">_Background Images</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="toolbars">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Toolbars...</property>
- <property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="toolbars_menu">
- <child>
- <widget class="GtkCheckMenuItem" id="menu_bar">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Menu Bar</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkCheckMenuItem" id="tool_bar">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Button Bar</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkCheckMenuItem" id="status_bar">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Status Bar</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator11">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="downloads">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Shows the downloads window</property>
- <property name="label" translatable="yes">_Downloads...</property>
- <property name="use_underline">True</property>
- <accelerator key="d" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="save_window_size">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Save this window's size and position for use with new windows.</property>
- <property name="label" translatable="yes">S_ave Window Size</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="debugging">
- <property name="visible">True</property>
- <property name="label" translatable="yes">De_bugging</property>
- <property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="debugging_menu">
- <child>
- <widget class="GtkMenuItem" id="toggle_debug_rendering">
- <property name="visible">True</property>
- <property name="label" translatable="yes">T_oggle debug rendering</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="save_box_tree">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Save box tree</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="save_dom_tree">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Save DOM tree</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
<child>
- <widget class="GtkMenuItem" id="menuitem_navigate">
+ <widget class="GtkMenuItem" id="menuitem_nav">
<property name="visible">True</property>
<property name="label" translatable="yes">_Navigate</property>
<property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="menuitem_navigate_menu">
- <child>
- <widget class="GtkImageMenuItem" id="back">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Back</property>
- <property name="use_underline">True</property>
- <accelerator key="Left" modifiers="GDK_MOD1_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image623">
- <property name="visible">True</property>
- <property name="stock">gtk-go-back</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="forward">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Forward</property>
- <property name="use_underline">True</property>
- <accelerator key="Right" modifiers="GDK_MOD1_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image624">
- <property name="visible">True</property>
- <property name="stock">gtk-go-forward</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="home">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Home</property>
- <property name="use_underline">True</property>
- <accelerator key="Down" modifiers="GDK_MOD1_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image625">
- <property name="visible">True</property>
- <property name="stock">gtk-home</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator7">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="local_history">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Show the history tree for this browser window.</property>
- <property name="label" translatable="yes">_Local history...</property>
- <property name="use_underline">True</property>
- <accelerator key="H" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="global_history">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Show the history tree for all windows.</property>
- <property name="label" translatable="yes">_Global history...</property>
- <property name="use_underline">True</property>
- <accelerator key="h" modifiers="GDK_SHIFT_MASK | GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator8">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="nsgtk_add_to_bookmarks">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Add the current page to your bookmarks.</property>
- <property name="label" translatable="yes">_Add to Bookmarks</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="show_bookmarks">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Open a window showing all your bookmarks.</property>
- <property name="label" translatable="yes">_Show Bookmarks...</property>
- <property name="use_underline">True</property>
- <accelerator key="F6" modifiers="" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator13">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="open_location">
- <property name="visible">True</property>
- <property name="tooltip" translatable="yes">Open an address into this browser window.</property>
- <property name="label" translatable="yes">_Open location...</property>
- <property name="use_underline">True</property>
- <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
<child>
@@ -680,41 +44,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">_Tabs</property>
<property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="menuitem_tabs_menu">
- <child>
- <widget class="GtkMenuItem" id="next_tab">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Next Tab</property>
- <property name="use_underline">True</property>
- <accelerator key="Right" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="prev_tab">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Previous Tab</property>
- <property name="use_underline">True</property>
- <accelerator key="Left" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="close_tab">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Close tab</property>
- <property name="use_underline">True</property>
- <accelerator key="W" modifiers="GDK_CONTROL_MASK" signal="activate"/>
- <child internal-child="image">
- <widget class="GtkImage" id="image626">
- <property name="visible">True</property>
- <property name="stock">gtk-close</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
<child>
@@ -722,56 +51,6 @@
<property name="visible">True</property>
<property name="label" translatable="yes">_Help</property>
<property name="use_underline">True</property>
- <child>
- <widget class="GtkMenu" id="menuitem_help_menu">
- <child>
- <widget class="GtkImageMenuItem" id="contents">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Shows the contents of the NetSurf manual.</property>
- <property name="label" translatable="yes">_Contents...</property>
- <property name="use_underline">True</property>
- <child internal-child="image">
- <widget class="GtkImage" id="image627">
- <property name="visible">True</property>
- <property name="stock">gtk-help</property>
- <property name="icon_size">1</property>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="guide">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="tooltip" translatable="yes">Shows a guide and tutorial.</property>
- <property name="label" translatable="yes">User _guide...</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="user_information">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="label" translatable="yes">User _information...</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkSeparatorMenuItem" id="separator9">
- <property name="visible">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkImageMenuItem" id="about">
- <property name="visible">True</property>
- <property name="label">gtk-about</property>
- <property name="use_underline">True</property>
- <property name="use_stock">True</property>
- </widget>
- </child>
- </widget>
- </child>
</widget>
</child>
</widget>
@@ -784,92 +63,123 @@
<widget class="GtkToolbar" id="toolbar">
<property name="visible">True</property>
<property name="toolbar_style">GTK_TOOLBAR_BOTH_HORIZ</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkToolbar" id="searchbar">
<child>
- <widget class="GtkToolButton" id="toolBack">
- <property name="visible">True</property>
- <property name="stock_id">gtk-go-back</property>
- </widget>
- <packing>
- <property name="homogeneous">True</property>
- </packing>
- </child>
- <child>
- <widget class="GtkToolButton" id="toolHistory">
+ <widget class="GtkToolButton" id="closeSearchButton">
<property name="visible">True</property>
- <property name="visible_horizontal">False</property>
- <property name="visible_vertical">False</property>
- <property name="is_important">True</property>
- <property name="icon">arrow_down_8x32.png</property>
+ <property name="stock_id">gtk-close</property>
</widget>
<packing>
- <property name="homogeneous">True</property>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
</packing>
</child>
<child>
- <widget class="GtkToolButton" id="toolForward">
+ <widget class="GtkToolItem" id="searchLabelItem">
<property name="visible">True</property>
- <property name="stock_id">gtk-go-forward</property>
+ <child>
+ <widget class="GtkLabel" id="searchlabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Match</property>
+ </widget>
+ </child>
</widget>
<packing>
- <property name="homogeneous">True</property>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
</packing>
</child>
<child>
- <widget class="GtkToolButton" id="toolStop">
+ <widget class="GtkToolItem" id="toolSearch">
<property name="visible">True</property>
- <property name="stock_id">gtk-stop</property>
+ <child>
+ <widget class="GtkEntry" id="searchEntry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ </widget>
+ </child>
</widget>
<packing>
- <property name="homogeneous">True</property>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
</packing>
</child>
<child>
- <widget class="GtkToolButton" id="toolReload">
+ <widget class="GtkToolButton" id="searchBackButton">
<property name="visible">True</property>
- <property name="stock_id">gtk-refresh</property>
+ <property name="label" translatable="yes">search _Back</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-back</property>
</widget>
<packing>
- <property name="homogeneous">True</property>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
</packing>
</child>
<child>
- <widget class="GtkToolButton" id="toolHome">
+ <widget class="GtkToolButton" id="searchForwardButton">
<property name="visible">True</property>
- <property name="stock_id">gtk-home</property>
+ <property name="label" translatable="yes">search _Forward</property>
+ <property name="use_underline">True</property>
+ <property name="stock_id">gtk-go-forward</property>
</widget>
<packing>
- <property name="homogeneous">True</property>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
</packing>
</child>
<child>
- <widget class="GtkToolItem" id="toolURLBar">
+ <widget class="GtkToolItem" id="checkAllSearchItem">
<property name="visible">True</property>
<child>
- <widget class="GtkEntry" id="URLBar">
+ <widget class="GtkCheckButton" id="checkAllSearch">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="has_focus">True</property>
+ <property name="tooltip" translatable="yes">show all matches</property>
+ <property name="label" translatable="yes">all </property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
</widget>
</child>
</widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
</child>
<child>
- <widget class="GtkToolItem" id="toolthrobber">
+ <widget class="GtkToolItem" id="caseSensItem">
<property name="visible">True</property>
<child>
- <widget class="GtkImage" id="throbber">
+ <widget class="GtkCheckButton" id="caseSensButton">
<property name="visible">True</property>
- <property name="xpad">2</property>
- <property name="icon_name">gtk-yes</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Match case when searching</property>
+ <property name="label" translatable="yes">case</property>
+ <property name="relief">GTK_RELIEF_NONE</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
</widget>
</child>
</widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">False</property>
+ </packing>
</child>
</widget>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">1</property>
+ <property name="position">2</property>
</packing>
</child>
<child>
@@ -907,7 +217,7 @@
</child>
</widget>
<packing>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
<child>
@@ -917,496 +227,60 @@
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
- <property name="position">3</property>
+ <property name="position">4</property>
</packing>
</child>
</widget>
</child>
</widget>
- <widget class="GtkDialog" id="wndLogin">
- <property name="title" translatable="yes">Site Authentication</property>
- <property name="window_position">GTK_WIN_POS_CENTER_ALWAYS</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox2">
+ <widget class="GtkMenu" id="menuPopup">
+ <child>
+ <widget class="GtkMenuItem" id="menupopup_file">
<property name="visible">True</property>
- <child>
- <widget class="GtkHBox" id="hbox12">
- <property name="visible">True</property>
- <property name="border_width">3</property>
- <child>
- <widget class="GtkImage" id="image3">
- <property name="visible">True</property>
- <property name="yalign">0.10000000149011612</property>
- <property name="xpad">12</property>
- <property name="icon_size">6</property>
- <property name="icon_name">gtk-dialog-authentication</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkTable" id="table5">
- <property name="visible">True</property>
- <property name="border_width">1</property>
- <property name="n_rows">4</property>
- <property name="n_columns">2</property>
- <property name="column_spacing">11</property>
- <property name="row_spacing">10</property>
- <child>
- <widget class="GtkLabel" id="labelLoginHost">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">moo.yoo.com</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label57">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Password</property>
- </widget>
- <packing>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label56">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Username</property>
- </widget>
- <packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label54">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Host</property>
- </widget>
- <packing>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label55">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Realm</property>
- </widget>
- <packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="labelLoginRealm">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">my sekr3t area</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkEntry" id="entryLoginPass">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
- <property name="activates_default">True</property>
- <property name="text" translatable="yes">opensesame</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkEntry" id="entryLoginUser">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="has_focus">True</property>
- <property name="text" translatable="yes">sesame</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="y_options"></property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">1</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area2">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <child>
- <widget class="GtkButton" id="buttonLoginCan">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="label">gtk-cancel</property>
- <property name="use_stock">True</property>
- <property name="response_id">-6</property>
- </widget>
- </child>
- <child>
- <widget class="GtkButton" id="buttonLoginOK">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="response_id">-5</property>
- <child>
- <widget class="GtkAlignment" id="alignment14">
- <property name="visible">True</property>
- <property name="can_default">True</property>
- <property name="has_default">True</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <child>
- <widget class="GtkHBox" id="hbox11">
- <property name="visible">True</property>
- <property name="spacing">2</property>
- <child>
- <widget class="GtkImage" id="image2">
- <property name="visible">True</property>
- <property name="stock">gtk-ok</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label49">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Login</property>
- <property name="use_underline">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
+ <property name="label" translatable="yes">File</property>
+ <property name="use_underline">True</property>
</widget>
</child>
- </widget>
- <widget class="GtkDialog" id="wndSSLProblem">
- <property name="border_width">1</property>
- <property name="title" translatable="yes">SSL certificate problem</property>
- <property name="modal">True</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <child internal-child="vbox">
- <widget class="GtkVBox" id="dialog-vbox3">
+ <child>
+ <widget class="GtkMenuItem" id="menupopup_edit">
<property name="visible">True</property>
- <child>
- <widget class="GtkHBox" id="hbox15">
- <property name="visible">True</property>
- <child>
- <widget class="GtkImage" id="image6">
- <property name="visible">True</property>
- <property name="yalign">0</property>
- <property name="icon_size">6</property>
- <property name="icon_name">gtk-dialog-warning</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkVBox" id="vbox13">
- <property name="visible">True</property>
- <child>
- <widget class="GtkLabel" id="label62">
- <property name="visible">True</property>
- <property name="label" translatable="yes">NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkFrame" id="frame13">
- <property name="visible">True</property>
- <property name="border_width">5</property>
- <property name="label_xalign">0</property>
- <child>
- <widget class="GtkAlignment" id="alignment17">
- <property name="visible">True</property>
- <property name="left_padding">12</property>
- <child>
- <widget class="GtkScrolledWindow" id="scrolledwindow1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="shadow_type">GTK_SHADOW_IN</property>
- <child>
- <widget class="GtkTextView" id="textview1">
- <property name="height_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">False</property>
- <property name="text" translatable="yes">(not implemented)</property>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkLabel" id="label63">
- <property name="visible">True</property>
- <property name="label" translatable="yes">&lt;b&gt;Certificate chain&lt;/b&gt;</property>
- <property name="use_markup">True</property>
- </widget>
- <packing>
- <property name="type">label_item</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">2</property>
- </packing>
- </child>
- <child internal-child="action_area">
- <widget class="GtkHButtonBox" id="dialog-action_area3">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <child>
- <widget class="GtkButton" id="sslreject">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="response_id">-6</property>
- <child>
- <widget class="GtkAlignment" id="alignment16">
- <property name="visible">True</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <child>
- <widget class="GtkHBox" id="hbox14">
- <property name="visible">True</property>
- <property name="spacing">2</property>
- <child>
- <widget class="GtkImage" id="image5">
- <property name="visible">True</property>
- <property name="stock">gtk-cancel</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label61">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Reject</property>
- <property name="use_underline">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkButton" id="sslaccept">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="response_id">-5</property>
- <child>
- <widget class="GtkAlignment" id="alignment15">
- <property name="visible">True</property>
- <property name="xscale">0</property>
- <property name="yscale">0</property>
- <child>
- <widget class="GtkHBox" id="hbox13">
- <property name="visible">True</property>
- <property name="spacing">2</property>
- <child>
- <widget class="GtkImage" id="image4">
- <property name="visible">True</property>
- <property name="stock">gtk-apply</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label60">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Accept</property>
- <property name="use_underline">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="pack_type">GTK_PACK_END</property>
- </packing>
- </child>
+ <property name="label" translatable="yes">Edit</property>
+ <property name="use_underline">True</property>
</widget>
</child>
- </widget>
- <widget class="GtkWindow" id="wndWarning">
- <property name="title" translatable="yes">Warning from NetSurf</property>
- <property name="window_position">GTK_WIN_POS_CENTER</property>
- <property name="icon_name">gtk-dialog-warning</property>
- <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
- <property name="urgency_hint">True</property>
<child>
- <widget class="GtkVBox" id="vbox32">
+ <widget class="GtkMenuItem" id="menupopup_view">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">View</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="menupopup_nav">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Navigate</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="menupopup_tabs">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Tabs</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkMenuItem" id="menupopup_help">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Help</property>
+ <property name="use_underline">True</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkSeparatorMenuItem" id="menupopup_sep">
<property name="visible">True</property>
- <property name="border_width">2</property>
- <child>
- <widget class="GtkHBox" id="hbox30">
- <property name="visible">True</property>
- <property name="border_width">3</property>
- <child>
- <widget class="GtkImage" id="image519">
- <property name="visible">True</property>
- <property name="xpad">12</property>
- <property name="icon_size">6</property>
- <property name="icon_name">gtk-dialog-warning</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="labelWarning">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Help help help! I'm being held prisoner by a bunch of RISC OS zealots!</property>
- <property name="wrap">True</property>
- </widget>
- <packing>
- <property name="padding">1</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkHSeparator" id="hseparator2">
- <property name="visible">True</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="padding">3</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHButtonBox" id="hbuttonbox2">
- <property name="visible">True</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <child>
- <widget class="GtkButton" id="button14">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="label">gtk-ok</property>
- <property name="use_stock">True</property>
- <property name="response_id">0</property>
- <signal name="clicked" handler="gtk_widget_hide" object="wndWarning"/>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
</widget>
</child>
- </widget>
- <widget class="GtkMenu" id="menuPopup">
<child>
<widget class="GtkMenuItem" id="open_link_in_focused_tab_popup">
<property name="visible">True</property>
@@ -1422,12 +296,12 @@
</widget>
</child>
<child>
- <widget class="GtkSeparatorMenuItem" id="separator1">
+ <widget class="GtkSeparatorMenuItem" id="sep2">
<property name="visible">True</property>
</widget>
</child>
<child>
- <widget class="GtkImageMenuItem" id="popupBack">
+ <widget class="GtkImageMenuItem" id="back_popup">
<property name="visible">True</property>
<property name="label" translatable="yes">_Back</property>
<property name="use_underline">True</property>
@@ -1441,7 +315,7 @@
</widget>
</child>
<child>
- <widget class="GtkImageMenuItem" id="popupForward">
+ <widget class="GtkImageMenuItem" id="forward_popup">
<property name="visible">True</property>
<property name="label" translatable="yes">_Forward</property>
<property name="use_underline">True</property>
@@ -1455,12 +329,12 @@
</widget>
</child>
<child>
- <widget class="GtkSeparatorMenuItem" id="separator">
+ <widget class="GtkSeparatorMenuItem" id="sep">
<property name="visible">True</property>
</widget>
</child>
<child>
- <widget class="GtkImageMenuItem" id="popupReload">
+ <widget class="GtkImageMenuItem" id="reload_popup">
<property name="visible">True</property>
<property name="label" translatable="yes">_Reload</property>
<property name="use_underline">True</property>
@@ -1530,316 +404,11 @@
</widget>
</child>
<child>
- <widget class="GtkMenuItem" id="menupopup_file">
- <property name="visible">True</property>
- <property name="label" translatable="yes">File</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="menupopup_edit">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Edit</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="menupopup_view">
- <property name="visible">True</property>
- <property name="label" translatable="yes">View</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="menupopup_navigate">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Navigate</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="menupopup_object">
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="label" translatable="yes">Object</property>
- <property name="use_underline">True</property>
- </widget>
- </child>
- <child>
- <widget class="GtkMenuItem" id="menupopup_help">
+ <widget class="GtkMenuItem" id="customize_popup">
<property name="visible">True</property>
- <property name="label" translatable="yes">Help</property>
+ <property name="label" translatable="yes">Customize..</property>
<property name="use_underline">True</property>
</widget>
</child>
</widget>
- <widget class="GtkWindow" id="wndPDFPassword">
- <property name="title" translatable="yes">PDF Password</property>
- <property name="modal">True</property>
- <property name="window_position">GTK_WIN_POS_CENTER</property>
- <child>
- <widget class="GtkHBox" id="hbox1">
- <property name="visible">True</property>
- <child>
- <widget class="GtkImage" id="image1">
- <property name="visible">True</property>
- <property name="yalign">0.10000000149011612</property>
- <property name="xpad">12</property>
- <property name="icon_size">6</property>
- <property name="icon_name">gtk-dialog-authentication</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkVBox" id="vbox1">
- <property name="visible">True</property>
- <property name="border_width">5</property>
- <child>
- <widget class="GtkLabel" id="labelInfo">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Write and confirm passwords:</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="hbox2">
- <property name="visible">True</property>
- <property name="border_width">5</property>
- <child>
- <widget class="GtkLabel" id="label4">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Owner password:</property>
- <property name="width_chars">15</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkEntry" id="entryPDFOwnerPassword">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="max_length">20</property>
- <property name="visibility">False</property>
- <property name="width_chars">20</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="hbox3">
- <property name="visible">True</property>
- <property name="border_width">5</property>
- <child>
- <widget class="GtkLabel" id="label5">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Repeat password:</property>
- <property name="width_chars">15</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkEntry" id="entryPDFOwnerPassword1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="max_length">20</property>
- <property name="visibility">False</property>
- <property name="width_chars">20</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="hbox4">
- <property name="visible">True</property>
- <property name="border_width">5</property>
- <child>
- <widget class="GtkLabel" id="label6">
- <property name="visible">True</property>
- <property name="label" translatable="yes">User password:</property>
- <property name="width_chars">15</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkEntry" id="entryPDFUserPassword">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="max_length">20</property>
- <property name="visibility">False</property>
- <property name="width_chars">20</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">3</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHBox" id="hbox5">
- <property name="visible">True</property>
- <property name="border_width">5</property>
- <child>
- <widget class="GtkLabel" id="label7">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Repeat password:</property>
- <property name="width_chars">15</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkEntry" id="entryPDFUserPassword1">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="max_length">20</property>
- <property name="visibility">False</property>
- <property name="width_chars">20</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">4</property>
- </packing>
- </child>
- <child>
- <widget class="GtkHButtonBox" id="hbuttonbox1">
- <property name="visible">True</property>
- <property name="border_width">5</property>
- <property name="spacing">10</property>
- <property name="layout_style">GTK_BUTTONBOX_END</property>
- <child>
- <widget class="GtkButton" id="buttonPDFSetPassword">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="response_id">0</property>
- <child>
- <widget class="GtkHBox" id="hbox7">
- <property name="visible">True</property>
- <child>
- <widget class="GtkImage" id="image7">
- <property name="visible">True</property>
- <property name="stock">gtk-ok</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label8">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Set password</property>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- <child>
- <widget class="GtkButton" id="buttonPDFNoPassword">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="response_id">0</property>
- <child>
- <widget class="GtkAlignment" id="alignment1">
- <property name="visible">True</property>
- <child>
- <widget class="GtkHBox" id="hbox6">
- <property name="visible">True</property>
- <child>
- <widget class="GtkImage" id="image8">
- <property name="visible">True</property>
- <property name="stock">gtk-cancel</property>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label9">
- <property name="visible">True</property>
- <property name="label" translatable="yes">No password</property>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">5</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
- </widget>
</glade-interface>
diff --git a/gtk/res/options.glade b/gtk/res/options.glade
index 6bc5cc41e..a1b0414f8 100644
--- a/gtk/res/options.glade
+++ b/gtk/res/options.glade
@@ -298,7 +298,7 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">Visited pages are kept in memory for this many days</property>
- <property name="adjustment">14 0 100 1 10 10</property>
+ <property name="adjustment">14 0 100 1 10 0</property>
<property name="climb_rate">1</property>
</widget>
<packing>
@@ -471,67 +471,30 @@
<property name="column_spacing">3</property>
<property name="row_spacing">3</property>
<child>
- <widget class="GtkEntry" id="entryProxyPassword">
+ <widget class="GtkEntry" id="entryProxyUser">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">If your proxy server requires authentication, enter your password here.</property>
- <property name="visibility">False</property>
+ <property name="tooltip" translatable="yes">If your proxy server requires authentication, enter your username here.</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label76">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Proxy type</property>
- </widget>
- <packing>
- <property name="x_options"></property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label75">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Host</property>
- </widget>
- <packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label74">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Username</property>
- </widget>
- <packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
- <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label73">
+ <widget class="GtkComboBox" id="comboProxyType">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Password</property>
+ <property name="items" translatable="yes">No proxy
+Simple proxy
+Basic authentication
+NTLM authentication</property>
</widget>
<packing>
- <property name="top_attach">3</property>
- <property name="bottom_attach">4</property>
- <property name="x_options"></property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
@@ -578,30 +541,67 @@
</packing>
</child>
<child>
- <widget class="GtkComboBox" id="comboProxyType">
+ <widget class="GtkLabel" id="label73">
<property name="visible">True</property>
- <property name="items" translatable="yes">No proxy
-Simple proxy
-Basic authentication
-NTLM authentication</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Password</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkEntry" id="entryProxyUser">
+ <widget class="GtkLabel" id="label74">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Username</property>
+ </widget>
+ <packing>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label75">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Host</property>
+ </widget>
+ <packing>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label76">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Proxy type</property>
+ </widget>
+ <packing>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entryProxyPassword">
<property name="visible">True</property>
<property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">If your proxy server requires authentication, enter your username here.</property>
+ <property name="tooltip" translatable="yes">If your proxy server requires authentication, enter your password here.</property>
+ <property name="visibility">False</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
<property name="y_options"></property>
</packing>
</child>
@@ -643,82 +643,82 @@ NTLM authentication</property>
<property name="column_spacing">3</property>
<property name="row_spacing">3</property>
<child>
- <widget class="GtkSpinButton" id="spinMaxFetchers">
+ <widget class="GtkLabel" id="label78">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Maximum number of concurrent items to fetch at once.</property>
- <property name="adjustment">1 0 100 1 10 10</property>
- <property name="climb_rate">1</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Maximum fetchers</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkSpinButton" id="spinFetchesPerHost">
+ <widget class="GtkLabel" id="label79">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Maximum number of item fetches per web server.</property>
- <property name="adjustment">1 0 100 1 10 10</property>
- <property name="climb_rate">1</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Fetches per host</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkSpinButton" id="spinCachedConnections">
+ <widget class="GtkLabel" id="label80">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Number of connections to keep incase they are needed again.</property>
- <property name="adjustment">1 0 100 1 10 10</property>
- <property name="climb_rate">1</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Cached connections</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label80">
+ <widget class="GtkSpinButton" id="spinCachedConnections">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Cached connections</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Number of connections to keep incase they are needed again.</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
+ <property name="climb_rate">1</property>
</widget>
<packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label79">
+ <widget class="GtkSpinButton" id="spinFetchesPerHost">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Fetches per host</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Maximum number of item fetches per web server.</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
+ <property name="climb_rate">1</property>
</widget>
<packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label78">
+ <widget class="GtkSpinButton" id="spinMaxFetchers">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Maximum fetchers</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Maximum number of concurrent items to fetch at once.</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
+ <property name="climb_rate">1</property>
</widget>
<packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
@@ -837,7 +837,7 @@ NTLM authentication</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">Do not update animations any more often than this.</property>
- <property name="adjustment">0 0 100 0.10000000149 1 1</property>
+ <property name="adjustment">0 0 100 0.10000000149 1 0</property>
<property name="climb_rate">1</property>
<property name="digits">1</property>
<property name="numeric">True</property>
@@ -934,85 +934,78 @@ NTLM authentication</property>
<property name="column_spacing">3</property>
<property name="row_spacing">3</property>
<child>
- <widget class="GtkFontButton" id="fontSansSerif">
+ <widget class="GtkLabel" id="label88">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="response_id">0</property>
- <property name="show_style">False</property>
- <property name="show_size">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Sans-serif</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkComboBox" id="comboDefault">
+ <widget class="GtkLabel" id="label89">
<property name="visible">True</property>
- <property name="items" translatable="yes">Sans-serif
-Serif
-Monospace
-Cursive
-Fantasy</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Serif</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">5</property>
- <property name="bottom_attach">6</property>
- <property name="x_options">GTK_FILL</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkFontButton" id="fontFantasy">
+ <widget class="GtkLabel" id="label90">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="response_id">0</property>
- <property name="show_style">False</property>
- <property name="show_size">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Monospace</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">4</property>
- <property name="bottom_attach">5</property>
- <property name="x_options">GTK_FILL</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkFontButton" id="fontCursive">
+ <widget class="GtkLabel" id="label91">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="response_id">0</property>
- <property name="show_style">False</property>
- <property name="show_size">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Cursive</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
- <property name="x_options">GTK_FILL</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkFontButton" id="fontMonospace">
+ <widget class="GtkLabel" id="label92">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="response_id">0</property>
- <property name="show_style">False</property>
- <property name="show_size">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Fantasy</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">GTK_FILL</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label93">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Default</property>
+ </widget>
+ <packing>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
@@ -1034,78 +1027,85 @@ Fantasy</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label93">
- <property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Default</property>
- </widget>
- <packing>
- <property name="top_attach">5</property>
- <property name="bottom_attach">6</property>
- <property name="x_options"></property>
- <property name="y_options"></property>
- </packing>
- </child>
- <child>
- <widget class="GtkLabel" id="label92">
+ <widget class="GtkFontButton" id="fontMonospace">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Fantasy</property>
+ <property name="can_focus">True</property>
+ <property name="response_id">0</property>
+ <property name="show_style">False</property>
+ <property name="show_size">False</property>
</widget>
<packing>
- <property name="top_attach">4</property>
- <property name="bottom_attach">5</property>
- <property name="x_options"></property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label91">
+ <widget class="GtkFontButton" id="fontCursive">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Cursive</property>
+ <property name="can_focus">True</property>
+ <property name="response_id">0</property>
+ <property name="show_style">False</property>
+ <property name="show_size">False</property>
</widget>
<packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="top_attach">3</property>
<property name="bottom_attach">4</property>
- <property name="x_options"></property>
+ <property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label90">
+ <widget class="GtkFontButton" id="fontFantasy">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Monospace</property>
+ <property name="can_focus">True</property>
+ <property name="response_id">0</property>
+ <property name="show_style">False</property>
+ <property name="show_size">False</property>
</widget>
<packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options"></property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label89">
+ <widget class="GtkComboBox" id="comboDefault">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Serif</property>
+ <property name="items" translatable="yes">Sans-serif
+Serif
+Monospace
+Cursive
+Fantasy</property>
</widget>
<packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options"></property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">GTK_FILL</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label88">
+ <widget class="GtkFontButton" id="fontSansSerif">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Sans-serif</property>
+ <property name="can_focus">True</property>
+ <property name="response_id">0</property>
+ <property name="show_style">False</property>
+ <property name="show_size">False</property>
</widget>
<packing>
- <property name="x_options"></property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="y_options"></property>
</packing>
</child>
@@ -1146,42 +1146,61 @@ Fantasy</property>
<property name="column_spacing">3</property>
<property name="row_spacing">3</property>
<child>
- <widget class="GtkLabel" id="label98">
+ <widget class="GtkButton" id="fontPreview">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">pt</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">View the changes in the browser window immediately.</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="border_width">2</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Preview</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
</widget>
<packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
- <property name="top_attach">1</property>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
<property name="bottom_attach">2</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
+ <property name="x_padding">2</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label97">
+ <widget class="GtkLabel" id="label95">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">pt</property>
+ <property name="label" translatable="yes">Default</property>
</widget>
<packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
+ <property name="x_options"></property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkSpinButton" id="spinMinimumSize">
+ <widget class="GtkLabel" id="label96">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Do not allow text to be displayed any smaller than this.</property>
- <property name="adjustment">1 0 100 1 10 10</property>
- <property name="climb_rate">1</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Minimum</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
@@ -1193,7 +1212,7 @@ Fantasy</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">The base-line font size to use.</property>
- <property name="adjustment">1 0 100 1 10 10</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
<property name="climb_rate">1</property>
</widget>
<packing>
@@ -1204,12 +1223,16 @@ Fantasy</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label96">
+ <widget class="GtkSpinButton" id="spinMinimumSize">
<property name="visible">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Minimum</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Do not allow text to be displayed any smaller than this.</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
+ <property name="climb_rate">1</property>
</widget>
<packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options"></property>
@@ -1217,52 +1240,29 @@ Fantasy</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label95">
+ <widget class="GtkLabel" id="label97">
<property name="visible">True</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">Default</property>
+ <property name="label" translatable="yes">pt</property>
</widget>
<packing>
- <property name="x_options"></property>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
<property name="y_options"></property>
</packing>
</child>
<child>
- <widget class="GtkButton" id="fontPreview">
+ <widget class="GtkLabel" id="label98">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">View the changes in the browser window immediately.</property>
- <property name="response_id">0</property>
- <child>
- <widget class="GtkHBox" id="hbox3">
- <property name="visible">True</property>
- <property name="border_width">2</property>
- <child>
- <widget class="GtkImage" id="image1">
- <property name="visible">True</property>
- <property name="stock">gtk-apply</property>
- </widget>
- </child>
- <child>
- <widget class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="label" translatable="yes">_Preview</property>
- <property name="use_underline">True</property>
- </widget>
- <packing>
- <property name="position">1</property>
- </packing>
- </child>
- </widget>
- </child>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">pt</property>
</widget>
<packing>
- <property name="left_attach">3</property>
- <property name="right_attach">4</property>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
<property name="bottom_attach">2</property>
- <property name="x_options"></property>
<property name="y_options"></property>
- <property name="x_padding">2</property>
</packing>
</child>
</widget>
@@ -1301,16 +1301,6 @@ Fantasy</property>
<property name="column_spacing">10</property>
<property name="row_spacing">3</property>
<child>
- <widget class="GtkLabel" id="label19">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Toolbar buttons</property>
- <property name="justify">GTK_JUSTIFY_RIGHT</property>
- </widget>
- <packing>
- <property name="x_options"></property>
- </packing>
- </child>
- <child>
<widget class="GtkComboBox" id="comboButtonType">
<property name="visible">True</property>
<property name="items" translatable="yes">Small icons
@@ -1325,6 +1315,16 @@ Text only</property>
<property name="y_options"></property>
</packing>
</child>
+ <child>
+ <widget class="GtkLabel" id="label19">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Toolbar buttons</property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ </widget>
+ <packing>
+ <property name="x_options"></property>
+ </packing>
+ </child>
</widget>
</child>
</widget>
@@ -1394,7 +1394,7 @@ Text only</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">How much memory to use for caching recently viewed objects in memory.</property>
- <property name="adjustment">1 0 100 1 10 10</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
<property name="climb_rate">1</property>
</widget>
<packing>
@@ -1467,7 +1467,7 @@ Text only</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">How long to keep cached items around on disc.</property>
- <property name="adjustment">1 0 100 1 10 10</property>
+ <property name="adjustment">1 0 100 1 10 0</property>
<property name="climb_rate">1</property>
</widget>
<packing>
@@ -1742,7 +1742,199 @@ Text only</property>
</packing>
</child>
<child>
- <placeholder/>
+ <widget class="GtkFrame" id="frame10">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment10">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkHBox" id="hbox11">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkRadioButton" id="sourceButtonWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">in own window </property>
+ <property name="response_id">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkRadioButton" id="sourceButtonTab">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">in new tab</property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label24">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;View Source&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame9">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment9">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkHBox" id="hbox9">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkCheckButton" id="checkUrlSearch">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">search from url bar </property>
+ <property name="response_id">0</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label23">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"> default provider</property>
+ <property name="justify">GTK_JUSTIFY_RIGHT</property>
+ </widget>
+ <packing>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkComboBox" id="comboSearch">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Google
+Yahoo!
+Microsoft live
+Business.com
+Omgili
+BBC News
+Ubuntu packages
+Creative commons
+Ask
+Answers
+Dictionary.com
+Youtube
+AeroMp3
+AOL
+Baidu
+Amazon
+Ebay
+IMDB
+Espn
+Wikipedia</property>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Search&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame11">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">GTK_SHADOW_NONE</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment11">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkHBox" id="themehbox">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkButton" id="buttonaddtheme">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">add theme..</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Select themes&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">4</property>
+ </packing>
</child>
</widget>
<packing>
@@ -1785,32 +1977,25 @@ Text only</property>
<property name="column_spacing">4</property>
<property name="row_spacing">5</property>
<child>
- <widget class="GtkLabel" id="label5">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Top:</property>
- </widget>
- </child>
- <child>
- <widget class="GtkLabel" id="label6">
+ <widget class="GtkLabel" id="label10">
<property name="visible">True</property>
- <property name="label" translatable="yes">Bottom:</property>
+ <property name="label" translatable="yes">mm</property>
</widget>
<packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
- <widget class="GtkSpinButton" id="spinMarginTop">
+ <widget class="GtkLabel" id="label9">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Set the top margin</property>
- <property name="adjustment">0 0 100 1 10 10</property>
- <property name="climb_rate">1</property>
+ <property name="label" translatable="yes">mm</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
</packing>
</child>
<child>
@@ -1818,7 +2003,7 @@ Text only</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">Set the bottom margin</property>
- <property name="adjustment">0 0 100 1 10 10</property>
+ <property name="adjustment">0 0 100 1 10 0</property>
<property name="climb_rate">1</property>
</widget>
<packing>
@@ -1829,27 +2014,34 @@ Text only</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label9">
+ <widget class="GtkSpinButton" id="spinMarginTop">
<property name="visible">True</property>
- <property name="label" translatable="yes">mm</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Set the top margin</property>
+ <property name="adjustment">0 0 100 1 10 0</property>
+ <property name="climb_rate">1</property>
</widget>
<packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label10">
+ <widget class="GtkLabel" id="label6">
<property name="visible">True</property>
- <property name="label" translatable="yes">mm</property>
+ <property name="label" translatable="yes">Bottom:</property>
</widget>
<packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Top:</property>
+ </widget>
+ </child>
</widget>
<packing>
<property name="expand">False</property>
@@ -1864,32 +2056,25 @@ Text only</property>
<property name="column_spacing">4</property>
<property name="row_spacing">5</property>
<child>
- <widget class="GtkLabel" id="label7">
- <property name="visible">True</property>
- <property name="label" translatable="yes">Left:</property>
- </widget>
- </child>
- <child>
- <widget class="GtkLabel" id="label8">
+ <widget class="GtkLabel" id="label12">
<property name="visible">True</property>
- <property name="label" translatable="yes">Right:</property>
+ <property name="label" translatable="yes">mm</property>
</widget>
<packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
<child>
- <widget class="GtkSpinButton" id="spinMarginLeft">
+ <widget class="GtkLabel" id="label11">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="tooltip" translatable="yes">Set the left margin</property>
- <property name="adjustment">0 0 100 1 10 10</property>
- <property name="climb_rate">1</property>
+ <property name="label" translatable="yes">mm</property>
</widget>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
</packing>
</child>
<child>
@@ -1897,7 +2082,7 @@ Text only</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">Set the right margin</property>
- <property name="adjustment">0 0 100 1 10 10</property>
+ <property name="adjustment">0 0 100 1 10 0</property>
<property name="climb_rate">1</property>
</widget>
<packing>
@@ -1908,27 +2093,34 @@ Text only</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label11">
+ <widget class="GtkSpinButton" id="spinMarginLeft">
<property name="visible">True</property>
- <property name="label" translatable="yes">mm</property>
+ <property name="can_focus">True</property>
+ <property name="tooltip" translatable="yes">Set the left margin</property>
+ <property name="adjustment">0 0 100 1 10 0</property>
+ <property name="climb_rate">1</property>
</widget>
<packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
</packing>
</child>
<child>
- <widget class="GtkLabel" id="label12">
+ <widget class="GtkLabel" id="label8">
<property name="visible">True</property>
- <property name="label" translatable="yes">mm</property>
+ <property name="label" translatable="yes">Right:</property>
</widget>
<packing>
- <property name="left_attach">2</property>
- <property name="right_attach">3</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
</packing>
</child>
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Left:</property>
+ </widget>
+ </child>
</widget>
<packing>
<property name="expand">False</property>
@@ -1983,7 +2175,7 @@ Text only</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip" translatable="yes">Set the scaling for the document - this way more content can fit in a page</property>
- <property name="adjustment">0 0 1000 1 10 10</property>
+ <property name="adjustment">0 0 1000 1 10 0</property>
<property name="climb_rate">1</property>
</widget>
<packing>
diff --git a/gtk/res/password.glade b/gtk/res/password.glade
new file mode 100644
index 000000000..0d00d65ed
--- /dev/null
+++ b/gtk/res/password.glade
@@ -0,0 +1,274 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="wndPDFPassword">
+ <property name="title" translatable="yes">PDF Password</property>
+ <property name="modal">True</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="yalign">0.10000000149011612</property>
+ <property name="xpad">12</property>
+ <property name="icon_size">6</property>
+ <property name="icon_name">gtk-dialog-authentication</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <widget class="GtkLabel" id="labelInfo">
+ <property name="visible">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Write and confirm passwords:</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Owner password:</property>
+ <property name="width_chars">15</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entryPDFOwnerPassword">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">20</property>
+ <property name="visibility">False</property>
+ <property name="width_chars">20</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox3">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Repeat password:</property>
+ <property name="width_chars">15</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entryPDFOwnerPassword1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">20</property>
+ <property name="visibility">False</property>
+ <property name="width_chars">20</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <widget class="GtkLabel" id="label6">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">User password:</property>
+ <property name="width_chars">15</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entryPDFUserPassword">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">20</property>
+ <property name="visibility">False</property>
+ <property name="width_chars">20</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Repeat password:</property>
+ <property name="width_chars">15</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkEntry" id="entryPDFUserPassword1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="max_length">20</property>
+ <property name="visibility">False</property>
+ <property name="width_chars">20</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="spacing">10</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="buttonPDFSetPassword">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox7">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image7">
+ <property name="visible">True</property>
+ <property name="stock">gtk-ok</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label8">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Set password</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="buttonPDFNoPassword">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment1">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image8">
+ <property name="visible">True</property>
+ <property name="stock">gtk-cancel</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label9">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">No password</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gtk/res/ssl.glade b/gtk/res/ssl.glade
new file mode 100644
index 000000000..98d9f9bf3
--- /dev/null
+++ b/gtk/res/ssl.glade
@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkDialog" id="wndSSLProblem">
+ <property name="border_width">1</property>
+ <property name="title" translatable="yes">SSL certificate problem</property>
+ <property name="modal">True</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkHBox" id="hbox15">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image6">
+ <property name="visible">True</property>
+ <property name="yalign">0</property>
+ <property name="icon_size">6</property>
+ <property name="icon_name">gtk-dialog-warning</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkVBox" id="vbox13">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="label62">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkFrame" id="frame13">
+ <property name="visible">True</property>
+ <property name="border_width">5</property>
+ <property name="label_xalign">0</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment17">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <child>
+ <widget class="GtkTextView" id="textview1">
+ <property name="height_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">False</property>
+ <property name="text" translatable="yes">(not implemented)</property>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label63">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Certificate chain&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </widget>
+ <packing>
+ <property name="type">label_item</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="sslreject">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="response_id">-6</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment16">
+ <property name="visible">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox14">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkImage" id="image5">
+ <property name="visible">True</property>
+ <property name="stock">gtk-cancel</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label61">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Reject</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkButton" id="sslaccept">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="response_id">-5</property>
+ <child>
+ <widget class="GtkAlignment" id="alignment15">
+ <property name="visible">True</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <child>
+ <widget class="GtkHBox" id="hbox13">
+ <property name="visible">True</property>
+ <property name="spacing">2</property>
+ <child>
+ <widget class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="label60">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Accept</property>
+ <property name="use_underline">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gtk/res/themelist b/gtk/res/themelist
new file mode 100644
index 000000000..4a70e25d6
--- /dev/null
+++ b/gtk/res/themelist
@@ -0,0 +1,2 @@
+gtk default theme
+gtk+
diff --git a/gtk/res/themes/Alpha.png b/gtk/res/themes/Alpha.png
new file mode 100644
index 000000000..f76e51dad
--- /dev/null
+++ b/gtk/res/themes/Alpha.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/back.png b/gtk/res/themes/gtk+/back.png
new file mode 100644
index 000000000..23b89b761
--- /dev/null
+++ b/gtk/res/themes/gtk+/back.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/closetab.png b/gtk/res/themes/gtk+/closetab.png
new file mode 100644
index 000000000..312b84dae
--- /dev/null
+++ b/gtk/res/themes/gtk+/closetab.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/closewindow.png b/gtk/res/themes/gtk+/closewindow.png
new file mode 100644
index 000000000..312b84dae
--- /dev/null
+++ b/gtk/res/themes/gtk+/closewindow.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/copy.png b/gtk/res/themes/gtk+/copy.png
new file mode 100644
index 000000000..a1178e64f
--- /dev/null
+++ b/gtk/res/themes/gtk+/copy.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/cut.png b/gtk/res/themes/gtk+/cut.png
new file mode 100644
index 000000000..82b105f80
--- /dev/null
+++ b/gtk/res/themes/gtk+/cut.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/delete.png b/gtk/res/themes/gtk+/delete.png
new file mode 100644
index 000000000..e375b894e
--- /dev/null
+++ b/gtk/res/themes/gtk+/delete.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/forward.png b/gtk/res/themes/gtk+/forward.png
new file mode 100644
index 000000000..727ff37f2
--- /dev/null
+++ b/gtk/res/themes/gtk+/forward.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/fullscreen.png b/gtk/res/themes/gtk+/fullscreen.png
new file mode 100644
index 000000000..21462fe0e
--- /dev/null
+++ b/gtk/res/themes/gtk+/fullscreen.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/helpabout.png b/gtk/res/themes/gtk+/helpabout.png
new file mode 100644
index 000000000..063d0df43
--- /dev/null
+++ b/gtk/res/themes/gtk+/helpabout.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/helpcontents.png b/gtk/res/themes/gtk+/helpcontents.png
new file mode 100644
index 000000000..b00fbd8c1
--- /dev/null
+++ b/gtk/res/themes/gtk+/helpcontents.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/history.png b/gtk/res/themes/gtk+/history.png
new file mode 100644
index 000000000..0d445027f
--- /dev/null
+++ b/gtk/res/themes/gtk+/history.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/home.png b/gtk/res/themes/gtk+/home.png
new file mode 100644
index 000000000..a2e0b3c96
--- /dev/null
+++ b/gtk/res/themes/gtk+/home.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/info b/gtk/res/themes/gtk+/info
new file mode 100644
index 000000000..36e4f09df
--- /dev/null
+++ b/gtk/res/themes/gtk+/info
@@ -0,0 +1,81 @@
+This file is part of NetSurf, http://www.netsurf-browser.org/
+
+The images in this theme folder 'gtk+' are from the gtk stock image set
+http://library.gnome.org/devel/gtk/unstable/gtk-Stock-Items.html
+
+the image history.png is [for what it's worth!] Copyright 2009 Mark Benjamin
+<netsurf-browser.org.MarkBenjamin@dfgh.net>
+
+NetSurf 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; version 2 of the License.
+
+NetSurf 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, see <http://www.gnu.org/licenses/>.
+
+*** Instructions for theming ***
+
+to create a theme, make a folder, whose name is the name of the theme;
+put in the folder, a set of png images for the toolbuttons;
+the names of the images should be a subset of the list
+
+ back.png,
+ history.png,
+ forward.png,
+ stop.png,
+ reload.png,
+ home.png,
+ newwindow.png,
+ newtab.png,
+ openfile.png,
+ closetab.png,
+ closewindow.png,
+ savepage.png,
+ pdf.png,
+ plaintext.png,
+ drawfile.png,
+ postscript.png,
+ printpreview.png,
+ print.png,
+ quit.png,
+ cut.png,
+ copy.png,
+ paste.png,
+ delete.png,
+ selectall.png,
+ find.png,
+ preferences.png,
+ zoomplus.png,
+ zoomminus.png,
+ zoomnormal.png,
+ fullscreen.png,
+ viewsource.png,
+ downloads.png,
+ savewindowsize.png,
+ toggledebugging.png,
+ saveboxtree.png,
+ savedomtree.png,
+ localhistory.png,
+ globalhistory.png,
+ addbookmarks.png,
+ showbookmarks.png,
+ openlocation.png,
+ nexttab.png,
+ prevtab.png,
+ contents.png,
+ guide.png,
+ info.png,
+ about.png,
+ searchback.png,
+ searchforward.png,
+ searchclose.png
+
+for local theming, the folder may be placed directly [as a subfolder] into the netsurf/gtk/res/themes folder; then 'add theme' from the preferences->advanced tab;
+
+for downloadable themes, compile netsurf/utils/container.c according to the instructions in the header of that file; make a netsurf container of the folder, serve it as content-type "application/x-netsurf-theme"; browse to it in NetSurf, then NetSurf should automatically install it
+
diff --git a/gtk/res/themes/gtk+/newtab.png b/gtk/res/themes/gtk+/newtab.png
new file mode 100644
index 000000000..c89e797b7
--- /dev/null
+++ b/gtk/res/themes/gtk+/newtab.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/newwindow.png b/gtk/res/themes/gtk+/newwindow.png
new file mode 100644
index 000000000..c89e797b7
--- /dev/null
+++ b/gtk/res/themes/gtk+/newwindow.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/openfile.png b/gtk/res/themes/gtk+/openfile.png
new file mode 100644
index 000000000..312e1187f
--- /dev/null
+++ b/gtk/res/themes/gtk+/openfile.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/paste.png b/gtk/res/themes/gtk+/paste.png
new file mode 100644
index 000000000..e938c3e99
--- /dev/null
+++ b/gtk/res/themes/gtk+/paste.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/preferences.png b/gtk/res/themes/gtk+/preferences.png
new file mode 100644
index 000000000..2596f3cc5
--- /dev/null
+++ b/gtk/res/themes/gtk+/preferences.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/print.png b/gtk/res/themes/gtk+/print.png
new file mode 100644
index 000000000..05d22d7a8
--- /dev/null
+++ b/gtk/res/themes/gtk+/print.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/printpreview.png b/gtk/res/themes/gtk+/printpreview.png
new file mode 100644
index 000000000..7f405de58
--- /dev/null
+++ b/gtk/res/themes/gtk+/printpreview.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/quit.png b/gtk/res/themes/gtk+/quit.png
new file mode 100644
index 000000000..0c9de64ba
--- /dev/null
+++ b/gtk/res/themes/gtk+/quit.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/reload.png b/gtk/res/themes/gtk+/reload.png
new file mode 100644
index 000000000..09b5df1d1
--- /dev/null
+++ b/gtk/res/themes/gtk+/reload.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/savepage.png b/gtk/res/themes/gtk+/savepage.png
new file mode 100644
index 000000000..5da8a02dc
--- /dev/null
+++ b/gtk/res/themes/gtk+/savepage.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/selectall.png b/gtk/res/themes/gtk+/selectall.png
new file mode 100644
index 000000000..1fc5b8282
--- /dev/null
+++ b/gtk/res/themes/gtk+/selectall.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/stop.png b/gtk/res/themes/gtk+/stop.png
new file mode 100644
index 000000000..54e1cb3e9
--- /dev/null
+++ b/gtk/res/themes/gtk+/stop.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/viewsource.png b/gtk/res/themes/gtk+/viewsource.png
new file mode 100644
index 000000000..9ddbe9b8e
--- /dev/null
+++ b/gtk/res/themes/gtk+/viewsource.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/zoomminus.png b/gtk/res/themes/gtk+/zoomminus.png
new file mode 100644
index 000000000..22afd1951
--- /dev/null
+++ b/gtk/res/themes/gtk+/zoomminus.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/zoomnormal.png b/gtk/res/themes/gtk+/zoomnormal.png
new file mode 100644
index 000000000..499cbd6c6
--- /dev/null
+++ b/gtk/res/themes/gtk+/zoomnormal.png
Binary files differ
diff --git a/gtk/res/themes/gtk+/zoomplus.png b/gtk/res/themes/gtk+/zoomplus.png
new file mode 100644
index 000000000..3a386fae7
--- /dev/null
+++ b/gtk/res/themes/gtk+/zoomplus.png
Binary files differ
diff --git a/gtk/res/toolbar.glade b/gtk/res/toolbar.glade
new file mode 100644
index 000000000..7e5ff0fb5
--- /dev/null
+++ b/gtk/res/toolbar.glade
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--Generated with glade3 3.4.5 on Tue Jun 9 08:21:40 2009 -->
+<glade-interface>
+ <widget class="GtkWindow" id="toolbarwindow">
+ <property name="width_request">700</property>
+ <property name="height_request">450</property>
+ <child>
+ <widget class="GtkVBox" id="windowvbox">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkLabel" id="toolbarlabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">move items from store to toolbar rearrange items in toolbar move items from toolbar to store</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <child>
+ <widget class="GtkViewport" id="viewport1">
+ <property name="visible">True</property>
+ <property name="resize_mode">GTK_RESIZE_QUEUE</property>
+ <child>
+ <widget class="GtkVBox" id="widgetvbox">
+ <property name="visible">True</property>
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHBox" id="buttonhbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <child>
+ <widget class="GtkButton" id="resetbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="response_id">0</property>
+ <child>
+ <widget class="GtkHBox" id="button1hbox">
+ <property name="visible">True</property>
+ <child>
+ <widget class="GtkImage" id="image1">
+ <property name="visible">True</property>
+ <property name="stock">gtk-refresh</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="refreshbuttonlabel">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">reset default</property>
+ </widget>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">10</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <widget class="GtkButton" id="okbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="has_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-apply</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">10</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkButton" id="cancelbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="label" translatable="yes">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gtk/res/warning.glade b/gtk/res/warning.glade
new file mode 100644
index 000000000..edfa18076
--- /dev/null
+++ b/gtk/res/warning.glade
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+ <widget class="GtkWindow" id="wndWarning">
+ <property name="title" translatable="yes">Warning from NetSurf</property>
+ <property name="window_position">GTK_WIN_POS_CENTER</property>
+ <property name="icon_name">gtk-dialog-warning</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="urgency_hint">True</property>
+ <child>
+ <widget class="GtkVBox" id="vbox32">
+ <property name="visible">True</property>
+ <property name="border_width">2</property>
+ <child>
+ <widget class="GtkHBox" id="hbox30">
+ <property name="visible">True</property>
+ <property name="border_width">3</property>
+ <child>
+ <widget class="GtkImage" id="image519">
+ <property name="visible">True</property>
+ <property name="xpad">12</property>
+ <property name="icon_size">6</property>
+ <property name="icon_name">gtk-dialog-warning</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkLabel" id="labelWarning">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Help help help! I'm being held prisoner by a bunch of RISC OS zealots!</property>
+ <property name="wrap">True</property>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ <child>
+ <widget class="GtkHSeparator" id="hseparator2">
+ <property name="visible">True</property>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="padding">3</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+ <child>
+ <widget class="GtkButton" id="button14">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="can_default">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="response_id">0</property>
+ <signal name="clicked" handler="gtk_widget_hide" object="wndWarning"/>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+</glade-interface>
diff --git a/gtk/sexy_icon_entry.c b/gtk/sexy_icon_entry.c
new file mode 100644
index 000000000..1dce22e31
--- /dev/null
+++ b/gtk/sexy_icon_entry.c
@@ -0,0 +1,979 @@
+/*
+ * libsexy/sexy-icon-entry.c Entry widget
+ * Copyright (C) 2004-2006 Christian Hammond.
+ * modified for NetSurf
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ * This file before modifications was originally part of LibSexy,
+ * http://www.chipx86.com/; it is redistributed under GPLv2
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>
+ * or write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "gtk/sexy_icon_entry.h"
+#include <string.h>
+#include <gtk/gtk.h>
+
+#define ICON_MARGIN 2
+#define MAX_ICONS 2
+
+#define IS_VALID_ICON_ENTRY_POSITION(pos) \
+ ((pos) == SEXY_ICON_ENTRY_PRIMARY || \
+ (pos) == SEXY_ICON_ENTRY_SECONDARY)
+
+typedef struct
+{
+ GtkImage *icon;
+ gboolean highlight;
+ gboolean hovered;
+ GdkWindow *window;
+
+} SexyIconInfo;
+
+struct _SexyIconEntryPriv
+{
+ SexyIconInfo icons[MAX_ICONS];
+
+ gulong icon_released_id;
+};
+
+enum
+{
+ ICON_PRESSED,
+ ICON_RELEASED,
+ LAST_SIGNAL
+};
+
+/* static void sexy_icon_entry_class_init(SexyIconEntryClass *klass); */
+static void sexy_icon_entry_editable_init(GtkEditableClass *iface);
+/* static void sexy_icon_entry_init(SexyIconEntry *entry); */
+static void sexy_icon_entry_finalize(GObject *obj);
+static void sexy_icon_entry_destroy(GtkObject *obj);
+static void sexy_icon_entry_map(GtkWidget *widget);
+static void sexy_icon_entry_unmap(GtkWidget *widget);
+static void sexy_icon_entry_realize(GtkWidget *widget);
+static void sexy_icon_entry_unrealize(GtkWidget *widget);
+static void sexy_icon_entry_size_request(GtkWidget *widget,
+ GtkRequisition *requisition);
+static void sexy_icon_entry_size_allocate(GtkWidget *widget,
+ GtkAllocation *allocation);
+static gint sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event);
+static gint sexy_icon_entry_enter_notify(GtkWidget *widget,
+ GdkEventCrossing *event);
+static gint sexy_icon_entry_leave_notify(GtkWidget *widget,
+ GdkEventCrossing *event);
+static gint sexy_icon_entry_button_press(GtkWidget *widget,
+ GdkEventButton *event);
+static gint sexy_icon_entry_button_release(GtkWidget *widget,
+ GdkEventButton *event);
+
+static GtkEntryClass *parent_class = NULL;
+static guint signals[LAST_SIGNAL] = {0};
+
+G_DEFINE_TYPE_EXTENDED(SexyIconEntry, sexy_icon_entry, GTK_TYPE_ENTRY,
+ 0,
+ G_IMPLEMENT_INTERFACE(GTK_TYPE_EDITABLE,
+ sexy_icon_entry_editable_init));
+
+void
+sexy_icon_entry_class_init(SexyIconEntryClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+ GtkEntryClass *entry_class;
+
+ parent_class = g_type_class_peek_parent(klass);
+
+ gobject_class = G_OBJECT_CLASS(klass);
+ object_class = GTK_OBJECT_CLASS(klass);
+ widget_class = GTK_WIDGET_CLASS(klass);
+ entry_class = GTK_ENTRY_CLASS(klass);
+
+ gobject_class->finalize = sexy_icon_entry_finalize;
+
+ object_class->destroy = sexy_icon_entry_destroy;
+
+ widget_class->map = sexy_icon_entry_map;
+ widget_class->unmap = sexy_icon_entry_unmap;
+ widget_class->realize = sexy_icon_entry_realize;
+ widget_class->unrealize = sexy_icon_entry_unrealize;
+ widget_class->size_request = sexy_icon_entry_size_request;
+ widget_class->size_allocate = sexy_icon_entry_size_allocate;
+ widget_class->expose_event = sexy_icon_entry_expose;
+ widget_class->enter_notify_event = sexy_icon_entry_enter_notify;
+ widget_class->leave_notify_event = sexy_icon_entry_leave_notify;
+ widget_class->button_press_event = sexy_icon_entry_button_press;
+ widget_class->button_release_event = sexy_icon_entry_button_release;
+
+ /**
+ * SexyIconEntry::icon-pressed:
+ * @entry: The entry on which the signal is emitted.
+ * @icon_pos: The position of the clicked icon.
+ * @button: The mouse button clicked.
+ *
+ * The ::icon-pressed signal is emitted when an icon is clicked.
+ */
+ /* signal modified to compile directly in NetSurf - param 8 of
+ * g_signal_new() changed from marshal type to NULL - so there may
+ * well be no working signal */
+ signals[ICON_PRESSED] =
+ g_signal_new("icon_pressed",
+ G_TYPE_FROM_CLASS(gobject_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(SexyIconEntryClass, icon_pressed),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 2,
+ G_TYPE_INT,
+ G_TYPE_INT);
+
+ /**
+ * SexyIconEntry::icon-released:
+ * @entry: The entry on which the signal is emitted.
+ * @icon_pos: The position of the clicked icon.
+ * @button: The mouse button clicked.
+ *
+ * The ::icon-released signal is emitted on the button release from a
+ * mouse click.
+ */
+ /* signal modified to compile directly in NetSurf - param 8 of
+ * g_signal_new() changed from marshal type to NULL - so there may
+ * well be no working signal */
+ signals[ICON_RELEASED] =
+ g_signal_new("icon_released",
+ G_TYPE_FROM_CLASS(gobject_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET(SexyIconEntryClass, icon_released),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 2,
+ G_TYPE_INT,
+ G_TYPE_INT);
+}
+
+static void
+sexy_icon_entry_editable_init(GtkEditableClass *iface)
+{
+};
+
+void
+sexy_icon_entry_init(SexyIconEntry *entry)
+{
+ entry->priv = g_new0(SexyIconEntryPriv, 1);
+}
+
+static void
+sexy_icon_entry_finalize(GObject *obj)
+{
+ SexyIconEntry *entry;
+
+ g_return_if_fail(obj != NULL);
+ g_return_if_fail(SEXY_IS_ICON_ENTRY(obj));
+
+ entry = SEXY_ICON_ENTRY(obj);
+
+ g_free(entry->priv);
+
+ if (G_OBJECT_CLASS(parent_class)->finalize)
+ G_OBJECT_CLASS(parent_class)->finalize(obj);
+}
+
+static void
+sexy_icon_entry_destroy(GtkObject *obj)
+{
+ SexyIconEntry *entry;
+
+ entry = SEXY_ICON_ENTRY(obj);
+
+ sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_PRIMARY, NULL);
+ sexy_icon_entry_set_icon(entry, SEXY_ICON_ENTRY_SECONDARY, NULL);
+
+ if (GTK_OBJECT_CLASS(parent_class)->destroy)
+ GTK_OBJECT_CLASS(parent_class)->destroy(obj);
+}
+
+static void
+sexy_icon_entry_map(GtkWidget *widget)
+{
+ if (GTK_WIDGET_REALIZED(widget) && !GTK_WIDGET_MAPPED(widget))
+ {
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ int i;
+
+ GTK_WIDGET_CLASS(parent_class)->map(widget);
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ if (entry->priv->icons[i].icon != NULL)
+ gdk_window_show(entry->priv->icons[i].window);
+ }
+ }
+}
+
+static void
+sexy_icon_entry_unmap(GtkWidget *widget)
+{
+ if (GTK_WIDGET_MAPPED(widget))
+ {
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ int i;
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ if (entry->priv->icons[i].icon != NULL)
+ gdk_window_hide(entry->priv->icons[i].window);
+ }
+
+ GTK_WIDGET_CLASS(parent_class)->unmap(widget);
+ }
+}
+
+static gint
+get_icon_width(SexyIconEntry *entry, SexyIconEntryPosition icon_pos)
+{
+ GtkRequisition requisition;
+ gint menu_icon_width;
+ gint width;
+ SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
+
+ if (icon_info->icon == NULL)
+ return 0;
+
+ gtk_widget_size_request(GTK_WIDGET(icon_info->icon), &requisition);
+ gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &menu_icon_width, NULL);
+
+ width = MAX(requisition.width, menu_icon_width);
+
+ return width;
+}
+
+static void
+get_borders(SexyIconEntry *entry, gint *xborder, gint *yborder)
+{
+ GtkWidget *widget = GTK_WIDGET(entry);
+ gint focus_width;
+ gboolean interior_focus;
+
+ gtk_widget_style_get(widget,
+ "interior-focus", &interior_focus,
+ "focus-line-width", &focus_width,
+ NULL);
+
+ if (gtk_entry_get_has_frame(GTK_ENTRY(entry)))
+ {
+ *xborder = widget->style->xthickness;
+ *yborder = widget->style->ythickness;
+ }
+ else
+ {
+ *xborder = 0;
+ *yborder = 0;
+ }
+
+ if (!interior_focus)
+ {
+ *xborder += focus_width;
+ *yborder += focus_width;
+ }
+}
+
+static void
+get_text_area_size(SexyIconEntry *entry, GtkAllocation *alloc)
+{
+ GtkWidget *widget = GTK_WIDGET(entry);
+ GtkRequisition requisition;
+ gint xborder, yborder;
+
+ gtk_widget_get_child_requisition(widget, &requisition);
+ get_borders(entry, &xborder, &yborder);
+
+ alloc->x = xborder;
+ alloc->y = yborder;
+ alloc->width = widget->allocation.width - xborder * 2;
+ alloc->height = requisition.height - yborder * 2;
+}
+
+static void
+get_icon_allocation(SexyIconEntry *icon_entry,
+ gboolean left,
+ GtkAllocation *widget_alloc,
+ GtkAllocation *text_area_alloc,
+ GtkAllocation *allocation,
+ SexyIconEntryPosition *icon_pos)
+{
+ gboolean rtl;
+
+ rtl = (gtk_widget_get_direction(GTK_WIDGET(icon_entry)) ==
+ GTK_TEXT_DIR_RTL);
+
+ if (left)
+ *icon_pos = (rtl ? SEXY_ICON_ENTRY_SECONDARY : SEXY_ICON_ENTRY_PRIMARY);
+ else
+ *icon_pos = (rtl ? SEXY_ICON_ENTRY_PRIMARY : SEXY_ICON_ENTRY_SECONDARY);
+
+ allocation->y = text_area_alloc->y;
+ allocation->width = get_icon_width(icon_entry, *icon_pos);
+ allocation->height = text_area_alloc->height;
+
+ if (left)
+ allocation->x = text_area_alloc->x + ICON_MARGIN;
+ else
+ {
+ allocation->x = text_area_alloc->x + text_area_alloc->width -
+ allocation->width - ICON_MARGIN;
+ }
+}
+
+static void
+sexy_icon_entry_realize(GtkWidget *widget)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+ int i;
+
+ GTK_WIDGET_CLASS(parent_class)->realize(widget);
+
+ attributes.x = 0;
+ attributes.y = 0;
+ attributes.width = 1;
+ attributes.height = 1;
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual(widget);
+ attributes.colormap = gtk_widget_get_colormap(widget);
+ attributes.event_mask = gtk_widget_get_events(widget);
+ attributes.event_mask |=
+ (GDK_EXPOSURE_MASK
+ | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
+ | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ SexyIconInfo *icon_info;
+
+ icon_info = &entry->priv->icons[i];
+ icon_info->window = gdk_window_new(widget->window, &attributes,
+ attributes_mask);
+ gdk_window_set_user_data(icon_info->window, widget);
+
+ gdk_window_set_background(icon_info->window,
+ &widget->style->base[GTK_WIDGET_STATE(widget)]);
+ }
+
+ gtk_widget_queue_resize(widget);
+}
+
+static void
+sexy_icon_entry_unrealize(GtkWidget *widget)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ int i;
+
+ GTK_WIDGET_CLASS(parent_class)->unrealize(widget);
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ SexyIconInfo *icon_info = &entry->priv->icons[i];
+
+ gdk_window_destroy(icon_info->window);
+ icon_info->window = NULL;
+ }
+}
+
+static void
+sexy_icon_entry_size_request(GtkWidget *widget, GtkRequisition *requisition)
+{
+ GtkEntry *gtkentry;
+ SexyIconEntry *entry;
+ gint icon_widths = 0;
+ int i;
+
+ gtkentry = GTK_ENTRY(widget);
+ entry = SEXY_ICON_ENTRY(widget);
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ int icon_width = get_icon_width(entry, i);
+
+ if (icon_width > 0)
+ icon_widths += icon_width + ICON_MARGIN;
+ }
+
+ GTK_WIDGET_CLASS(parent_class)->size_request(widget, requisition);
+
+ if (icon_widths > requisition->width)
+ requisition->width += icon_widths;
+}
+
+static void
+place_windows(SexyIconEntry *icon_entry, GtkAllocation *widget_alloc)
+{
+ SexyIconEntryPosition left_icon_pos;
+ SexyIconEntryPosition right_icon_pos;
+ GtkAllocation left_icon_alloc;
+ GtkAllocation right_icon_alloc;
+ GtkAllocation text_area_alloc;
+
+ get_text_area_size(icon_entry, &text_area_alloc);
+ get_icon_allocation(icon_entry, TRUE, widget_alloc, &text_area_alloc,
+ &left_icon_alloc, &left_icon_pos);
+ get_icon_allocation(icon_entry, FALSE, widget_alloc, &text_area_alloc,
+ &right_icon_alloc, &right_icon_pos);
+
+ if (left_icon_alloc.width > 0)
+ {
+ text_area_alloc.x = left_icon_alloc.x + left_icon_alloc.width +
+ ICON_MARGIN;
+ }
+
+ if (right_icon_alloc.width > 0)
+ text_area_alloc.width -= right_icon_alloc.width + ICON_MARGIN;
+
+ text_area_alloc.width -= text_area_alloc.x;
+
+ gdk_window_move_resize(icon_entry->priv->icons[left_icon_pos].window,
+ left_icon_alloc.x, left_icon_alloc.y,
+ left_icon_alloc.width, left_icon_alloc.height);
+
+ gdk_window_move_resize(icon_entry->priv->icons[right_icon_pos].window,
+ right_icon_alloc.x, right_icon_alloc.y,
+ right_icon_alloc.width, right_icon_alloc.height);
+
+ gdk_window_move_resize(GTK_ENTRY(icon_entry)->text_area,
+ text_area_alloc.x, text_area_alloc.y,
+ text_area_alloc.width, text_area_alloc.height);
+}
+
+static void
+sexy_icon_entry_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+ g_return_if_fail(SEXY_IS_ICON_ENTRY(widget));
+ g_return_if_fail(allocation != NULL);
+
+ widget->allocation = *allocation;
+
+ GTK_WIDGET_CLASS(parent_class)->size_allocate(widget, allocation);
+
+ if (GTK_WIDGET_REALIZED(widget))
+ place_windows(SEXY_ICON_ENTRY(widget), allocation);
+}
+
+static GdkPixbuf *
+get_pixbuf_from_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos)
+{
+ GdkPixbuf *pixbuf = NULL;
+ gchar *stock_id;
+ SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
+ GtkIconSize size;
+
+ switch (gtk_image_get_storage_type(GTK_IMAGE(icon_info->icon)))
+ {
+ case GTK_IMAGE_PIXBUF:
+ pixbuf = gtk_image_get_pixbuf(GTK_IMAGE(icon_info->icon));
+ g_object_ref(pixbuf);
+ break;
+
+ case GTK_IMAGE_STOCK:
+ gtk_image_get_stock(GTK_IMAGE(icon_info->icon), &stock_id, &size);
+ pixbuf = gtk_widget_render_icon(GTK_WIDGET(entry),
+ stock_id, size, NULL);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ return pixbuf;
+}
+
+/* Kudos to the gnome-panel guys. */
+static void
+colorshift_pixbuf(GdkPixbuf *dest, GdkPixbuf *src, int shift)
+{
+ gint i, j;
+ gint width, height, has_alpha, src_rowstride, dest_rowstride;
+ guchar *target_pixels;
+ guchar *original_pixels;
+ guchar *pix_src;
+ guchar *pix_dest;
+ int val;
+ guchar r, g, b;
+
+ has_alpha = gdk_pixbuf_get_has_alpha(src);
+ width = gdk_pixbuf_get_width(src);
+ height = gdk_pixbuf_get_height(src);
+ src_rowstride = gdk_pixbuf_get_rowstride(src);
+ dest_rowstride = gdk_pixbuf_get_rowstride(dest);
+ original_pixels = gdk_pixbuf_get_pixels(src);
+ target_pixels = gdk_pixbuf_get_pixels(dest);
+
+ for (i = 0; i < height; i++)
+ {
+ pix_dest = target_pixels + i * dest_rowstride;
+ pix_src = original_pixels + i * src_rowstride;
+
+ for (j = 0; j < width; j++)
+ {
+ r = *(pix_src++);
+ g = *(pix_src++);
+ b = *(pix_src++);
+
+ val = r + shift;
+ *(pix_dest++) = CLAMP(val, 0, 255);
+
+ val = g + shift;
+ *(pix_dest++) = CLAMP(val, 0, 255);
+
+ val = b + shift;
+ *(pix_dest++) = CLAMP(val, 0, 255);
+
+ if (has_alpha)
+ *(pix_dest++) = *(pix_src++);
+ }
+ }
+}
+
+static void
+draw_icon(GtkWidget *widget, SexyIconEntryPosition icon_pos)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ SexyIconInfo *icon_info = &entry->priv->icons[icon_pos];
+ GdkPixbuf *pixbuf;
+ gint x, y, width, height;
+
+ if (icon_info->icon == NULL || !GTK_WIDGET_REALIZED(widget))
+ return;
+
+ if ((pixbuf = get_pixbuf_from_icon(entry, icon_pos)) == NULL)
+ return;
+
+ gdk_drawable_get_size(icon_info->window, &width, &height);
+
+ if (width == 1 || height == 1)
+ {
+ /*
+ * size_allocate hasn't been called yet. These are the default values.
+ */
+ return;
+ }
+
+ if (gdk_pixbuf_get_height(pixbuf) > height)
+ {
+ GdkPixbuf *temp_pixbuf;
+ int scale;
+
+ scale = height - (2 * ICON_MARGIN);
+
+ temp_pixbuf = gdk_pixbuf_scale_simple(pixbuf, scale, scale,
+ GDK_INTERP_BILINEAR);
+
+ g_object_unref(pixbuf);
+
+ pixbuf = temp_pixbuf;
+ }
+
+ x = (width - gdk_pixbuf_get_width(pixbuf)) / 2;
+ y = (height - gdk_pixbuf_get_height(pixbuf)) / 2;
+
+ if (icon_info->hovered)
+ {
+ GdkPixbuf *temp_pixbuf;
+
+ temp_pixbuf = gdk_pixbuf_copy(pixbuf);
+
+ colorshift_pixbuf(temp_pixbuf, pixbuf, 30);
+
+ g_object_unref(pixbuf);
+
+ pixbuf = temp_pixbuf;
+ }
+
+ gdk_draw_pixbuf(icon_info->window, widget->style->black_gc, pixbuf,
+ 0, 0, x, y, -1, -1,
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+
+ g_object_unref(pixbuf);
+}
+
+static gint
+sexy_icon_entry_expose(GtkWidget *widget, GdkEventExpose *event)
+{
+ SexyIconEntry *entry;
+
+ g_return_val_if_fail(SEXY_IS_ICON_ENTRY(widget), FALSE);
+ g_return_val_if_fail(event != NULL, FALSE);
+
+ entry = SEXY_ICON_ENTRY(widget);
+
+ if (GTK_WIDGET_DRAWABLE(widget))
+ {
+ gboolean found = FALSE;
+ int i;
+
+ for (i = 0; i < MAX_ICONS && !found; i++)
+ {
+ SexyIconInfo *icon_info = &entry->priv->icons[i];
+
+ if (event->window == icon_info->window)
+ {
+ gint width;
+ GtkAllocation text_area_alloc;
+
+ get_text_area_size(entry, &text_area_alloc);
+ gdk_drawable_get_size(icon_info->window, &width, NULL);
+
+ gtk_paint_flat_box(widget->style, icon_info->window,
+ GTK_WIDGET_STATE(widget), GTK_SHADOW_NONE,
+ NULL, widget, "entry_bg",
+ 0, 0, width, text_area_alloc.height);
+
+ draw_icon(widget, i);
+
+ found = TRUE;
+ }
+ }
+
+ if (!found)
+ GTK_WIDGET_CLASS(parent_class)->expose_event(widget, event);
+ }
+
+ return FALSE;
+}
+
+static void
+update_icon(GObject *obj, GParamSpec *param, SexyIconEntry *entry)
+{
+ if (param != NULL)
+ {
+ const char *name = g_param_spec_get_name(param);
+
+ if (strcmp(name, "pixbuf") && strcmp(name, "stock") &&
+ strcmp(name, "image") && strcmp(name, "pixmap") &&
+ strcmp(name, "icon_set") && strcmp(name, "pixbuf_animation"))
+ {
+ return;
+ }
+ }
+
+ gtk_widget_queue_resize(GTK_WIDGET(entry));
+}
+
+static gint
+sexy_icon_entry_enter_notify(GtkWidget *widget, GdkEventCrossing *event)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ int i;
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ if (event->window == entry->priv->icons[i].window)
+ {
+ if (sexy_icon_entry_get_icon_highlight(entry, i))
+ {
+ entry->priv->icons[i].hovered = TRUE;
+
+ update_icon(NULL, NULL, entry);
+
+ break;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static gint
+sexy_icon_entry_leave_notify(GtkWidget *widget, GdkEventCrossing *event)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ int i;
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ if (event->window == entry->priv->icons[i].window)
+ {
+ if (sexy_icon_entry_get_icon_highlight(entry, i))
+ {
+ entry->priv->icons[i].hovered = FALSE;
+
+ update_icon(NULL, NULL, entry);
+
+ break;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+static gint
+sexy_icon_entry_button_press(GtkWidget *widget, GdkEventButton *event)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ int i;
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ if (event->window == entry->priv->icons[i].window)
+ {
+ if (event->button == 1 &&
+ sexy_icon_entry_get_icon_highlight(entry, i))
+ {
+ entry->priv->icons[i].hovered = FALSE;
+
+ update_icon(NULL, NULL, entry);
+ }
+
+ g_signal_emit(entry, signals[ICON_PRESSED], 0, i, event->button);
+
+ return TRUE;
+ }
+ }
+
+ if (GTK_WIDGET_CLASS(parent_class)->button_press_event)
+ return GTK_WIDGET_CLASS(parent_class)->button_press_event(widget,
+ event);
+
+ return FALSE;
+}
+
+static gint
+sexy_icon_entry_button_release(GtkWidget *widget, GdkEventButton *event)
+{
+ SexyIconEntry *entry = SEXY_ICON_ENTRY(widget);
+ int i;
+
+ for (i = 0; i < MAX_ICONS; i++)
+ {
+ GdkWindow *icon_window = entry->priv->icons[i].window;
+
+ if (event->window == icon_window)
+ {
+ int width, height;
+ gdk_drawable_get_size(icon_window, &width, &height);
+
+ if (event->button == 1 &&
+ sexy_icon_entry_get_icon_highlight(entry, i) &&
+ event->x >= 0 && event->y >= 0 &&
+ event->x <= width && event->y <= height)
+ {
+ entry->priv->icons[i].hovered = TRUE;
+
+ update_icon(NULL, NULL, entry);
+ }
+
+ g_signal_emit(entry, signals[ICON_RELEASED], 0, i, event->button);
+
+ return TRUE;
+ }
+ }
+
+ if (GTK_WIDGET_CLASS(parent_class)->button_release_event)
+ return GTK_WIDGET_CLASS(parent_class)->button_release_event(widget,
+ event);
+
+ return FALSE;
+}
+
+/**
+ * sexy_icon_entry_new
+ *
+ * Creates a new SexyIconEntry widget.
+ *
+ * Returns a new #SexyIconEntry.
+ */
+GtkWidget *
+sexy_icon_entry_new(void)
+{
+ return GTK_WIDGET(g_object_new(SEXY_TYPE_ICON_ENTRY, NULL));
+}
+
+/**
+ * sexy_icon_entry_set_icon
+ * @entry: A #SexyIconEntry.
+ * @position: Icon position.
+ * @icon: A #GtkImage to set as the icon.
+ *
+ * Sets the icon shown in the entry
+ */
+void
+sexy_icon_entry_set_icon(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,
+ GtkImage *icon)
+{
+ SexyIconInfo *icon_info;
+
+ g_return_if_fail(entry != NULL);
+ g_return_if_fail(SEXY_IS_ICON_ENTRY(entry));
+ g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos));
+ g_return_if_fail(icon == NULL || GTK_IS_IMAGE(icon));
+
+ icon_info = &entry->priv->icons[icon_pos];
+
+ if (icon == icon_info->icon)
+ return;
+
+ if (icon_pos == SEXY_ICON_ENTRY_SECONDARY &&
+ entry->priv->icon_released_id != 0)
+ {
+ g_signal_handler_disconnect(entry, entry->priv->icon_released_id);
+ entry->priv->icon_released_id = 0;
+ }
+
+ if (icon == NULL)
+ {
+ if (icon_info->icon != NULL)
+ {
+ gtk_widget_destroy(GTK_WIDGET(icon_info->icon));
+ icon_info->icon = NULL;
+
+ /*
+ * Explicitly check, as the pointer may become invalidated
+ * during destruction.
+ */
+ if (icon_info->window != NULL && GDK_IS_WINDOW(icon_info->window))
+ gdk_window_hide(icon_info->window);
+ }
+ }
+ else
+ {
+ if (icon_info->window != NULL && icon_info->icon == NULL)
+ gdk_window_show(icon_info->window);
+
+ g_signal_connect(G_OBJECT(icon), "notify",
+ G_CALLBACK(update_icon), entry);
+
+ icon_info->icon = icon;
+ g_object_ref(icon);
+ }
+
+ update_icon(NULL, NULL, entry);
+}
+
+/**
+ * sexy_icon_entry_set_icon_highlight
+ * @entry: A #SexyIconEntry;
+ * @position: Icon position.
+ * @highlight: TRUE if the icon should highlight on mouse-over
+ *
+ * Determines whether the icon will highlight on mouse-over.
+ */
+void
+sexy_icon_entry_set_icon_highlight(SexyIconEntry *entry,
+ SexyIconEntryPosition icon_pos,
+ gboolean highlight)
+{
+ SexyIconInfo *icon_info;
+
+ g_return_if_fail(entry != NULL);
+ g_return_if_fail(SEXY_IS_ICON_ENTRY(entry));
+ g_return_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos));
+
+ icon_info = &entry->priv->icons[icon_pos];
+
+ if (icon_info->highlight == highlight)
+ return;
+
+ icon_info->highlight = highlight;
+}
+
+/**
+ * sexy_icon_entry_get_icon
+ * @entry: A #SexyIconEntry.
+ * @position: Icon position.
+ *
+ * Retrieves the image used for the icon
+ *
+ * Returns: A #GtkImage.
+ */
+GtkImage *
+sexy_icon_entry_get_icon(const SexyIconEntry *entry,
+ SexyIconEntryPosition icon_pos)
+{
+ g_return_val_if_fail(entry != NULL, NULL);
+ g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), NULL);
+ g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), NULL);
+
+ return entry->priv->icons[icon_pos].icon;
+}
+
+/**
+ * sexy_icon_entry_get_icon_highlight
+ * @entry: A #SexyIconEntry.
+ * @position: Icon position.
+ *
+ * Retrieves whether entry will highlight the icon on mouseover.
+ *
+ * Returns: TRUE if icon highlights.
+ */
+gboolean
+sexy_icon_entry_get_icon_highlight(const SexyIconEntry *entry,
+ SexyIconEntryPosition icon_pos)
+{
+ g_return_val_if_fail(entry != NULL, FALSE);
+ g_return_val_if_fail(SEXY_IS_ICON_ENTRY(entry), FALSE);
+ g_return_val_if_fail(IS_VALID_ICON_ENTRY_POSITION(icon_pos), FALSE);
+
+ return entry->priv->icons[icon_pos].highlight;
+}
+
+static void
+clear_button_clicked_cb(SexyIconEntry *icon_entry,
+ SexyIconEntryPosition icon_pos,
+ int button)
+{
+ if (icon_pos != SEXY_ICON_ENTRY_SECONDARY || button != 1)
+ return;
+
+ gtk_entry_set_text(GTK_ENTRY(icon_entry), "");
+}
+
+/**
+ * sexy_icon_entry_add_clear_button
+ * @icon_entry: A #SexyIconEntry.
+ *
+ * A convenience function to add a clear button to the end of the entry.
+ * This is useful for search boxes.
+ */
+void
+sexy_icon_entry_add_clear_button(SexyIconEntry *icon_entry)
+{
+ GtkWidget *icon;
+
+ g_return_if_fail(icon_entry != NULL);
+ g_return_if_fail(SEXY_IS_ICON_ENTRY(icon_entry));
+
+ icon = gtk_image_new_from_stock(GTK_STOCK_CLEAR, GTK_ICON_SIZE_MENU);
+ gtk_widget_show(icon);
+ sexy_icon_entry_set_icon(SEXY_ICON_ENTRY(icon_entry),
+ SEXY_ICON_ENTRY_SECONDARY,
+ GTK_IMAGE(icon));
+ sexy_icon_entry_set_icon_highlight(SEXY_ICON_ENTRY(icon_entry),
+ SEXY_ICON_ENTRY_SECONDARY, TRUE);
+
+ if (icon_entry->priv->icon_released_id != 0)
+ {
+ g_signal_handler_disconnect(icon_entry,
+ icon_entry->priv->icon_released_id);
+ }
+
+ icon_entry->priv->icon_released_id =
+ g_signal_connect(G_OBJECT(icon_entry), "icon_released",
+ G_CALLBACK(clear_button_clicked_cb), NULL);
+}
diff --git a/gtk/sexy_icon_entry.h b/gtk/sexy_icon_entry.h
new file mode 100644
index 000000000..94ba90833
--- /dev/null
+++ b/gtk/sexy_icon_entry.h
@@ -0,0 +1,101 @@
+/*
+ * file libsexy/sexy-icon-entry.h Entry widget
+ *
+ * Copyright (C) 2004-2006 Christian Hammond.
+ * redistributed under GPLv2
+ *
+ * libsexy 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>
+ * or write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#ifndef _SEXY_ICON_ENTRY_H_
+#define _SEXY_ICON_ENTRY_H_
+
+typedef struct _SexyIconEntry SexyIconEntry;
+typedef struct _SexyIconEntryClass SexyIconEntryClass;
+typedef struct _SexyIconEntryPriv SexyIconEntryPriv;
+
+#include <gtk/gtkentry.h>
+#include <gtk/gtkimage.h>
+
+#define SEXY_TYPE_ICON_ENTRY (sexy_icon_entry_get_type())
+#define SEXY_ICON_ENTRY(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), SEXY_TYPE_ICON_ENTRY, SexyIconEntry))
+#define SEXY_ICON_ENTRY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), SEXY_TYPE_ICON_ENTRY, SexyIconEntryClass))
+#define SEXY_IS_ICON_ENTRY(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), SEXY_TYPE_ICON_ENTRY))
+#define SEXY_IS_ICON_ENTRY_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), SEXY_TYPE_ICON_ENTRY))
+#define SEXY_ICON_ENTRY_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), SEXY_TYPE_ICON_ENTRY, SexyIconEntryClass))
+
+typedef enum
+{
+ SEXY_ICON_ENTRY_PRIMARY,
+ SEXY_ICON_ENTRY_SECONDARY
+
+} SexyIconEntryPosition;
+
+struct _SexyIconEntry
+{
+ GtkEntry parent_object;
+
+ SexyIconEntryPriv *priv;
+
+ void (*gtk_reserved1)(void);
+ void (*gtk_reserved2)(void);
+ void (*gtk_reserved3)(void);
+ void (*gtk_reserved4)(void);
+};
+
+struct _SexyIconEntryClass
+{
+ GtkEntryClass parent_class;
+
+ /* Signals */
+ void (*icon_pressed)(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,
+ int button);
+ void (*icon_released)(SexyIconEntry *entry, SexyIconEntryPosition icon_pos,
+ int button);
+
+ void (*gtk_reserved1)(void);
+ void (*gtk_reserved2)(void);
+ void (*gtk_reserved3)(void);
+ void (*gtk_reserved4)(void);
+};
+
+G_BEGIN_DECLS
+
+GType sexy_icon_entry_get_type(void);
+
+GtkWidget *sexy_icon_entry_new(void);
+
+void sexy_icon_entry_set_icon(SexyIconEntry *entry,
+ SexyIconEntryPosition position,
+ GtkImage *icon);
+
+void sexy_icon_entry_set_icon_highlight(SexyIconEntry *entry,
+ SexyIconEntryPosition position,
+ gboolean highlight);
+
+GtkImage *sexy_icon_entry_get_icon(const SexyIconEntry *entry,
+ SexyIconEntryPosition position);
+
+gboolean sexy_icon_entry_get_icon_highlight(const SexyIconEntry *entry,
+ SexyIconEntryPosition position);
+void sexy_icon_entry_add_clear_button(SexyIconEntry *icon_entry);
+
+G_END_DECLS
+
+#endif /* _SEXY_ICON_ENTRY_H_ */
diff --git a/image/ico.c b/image/ico.c
index 5416e612a..e2fce245a 100644
--- a/image/ico.c
+++ b/image/ico.c
@@ -115,6 +115,18 @@ bool nsico_redraw(struct content *c, int x, int y,
background_colour, BITMAPF_NONE);
}
+/** sets the bitmap for an ico according to the dimensions */
+
+bool nsico_set_bitmap_from_size(struct content *c, int width, int height)
+{
+ struct bmp_image *bmp = ico_find(c->data.ico.ico, width, height);
+ if (bmp == NULL)
+ return false;
+ if ((bmp->decoded == false) && (bmp_decode(bmp) != BMP_OK))
+ return false;
+ c->bitmap = bmp->bitmap;
+ return true;
+}
bool nsico_redraw_tiled(struct content *c, int x, int y,
int width, int height,
diff --git a/image/ico.h b/image/ico.h
index cd7b0b432..f3686c0c5 100644
--- a/image/ico.h
+++ b/image/ico.h
@@ -48,6 +48,7 @@ bool nsico_redraw_tiled(struct content *c, int x, int y,
int clip_x0, int clip_y0, int clip_x1, int clip_y1,
float scale, colour background_colour,
bool repeat_x, bool repeat_y);
+bool nsico_set_bitmap_from_size(struct content *c, int width, int height);
#endif /* WITH_BMP */
diff --git a/render/favicon.c b/render/favicon.c
new file mode 100644
index 000000000..fdf6e25f1
--- /dev/null
+++ b/render/favicon.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2007 James Bursa <bursa@users.sourceforge.net>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include "content/fetch.h"
+#include "content/fetchcache.h"
+#include "render/favicon.h"
+#include "render/html.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/talloc.h"
+#include "utils/url.h"
+#include "utils/utils.h"
+
+static char *favicon_get_icon_ref(struct content *c, xmlNode *html);
+static void favicon_callback(content_msg msg, struct content *icon,
+ intptr_t p1, intptr_t p2, union content_msg_data data);
+
+/**
+ * retrieve 1 url reference to 1 favicon
+ * \param html xml node of html element
+ * \return pointer to url; NULL for no icon; caller owns returned pointer
+ */
+char *favicon_get_icon_ref(struct content *c, xmlNode *html)
+{
+ xmlNode *node;
+ char *rel, *href, *url, *url2;
+ url2 = NULL;
+ url_func_result res;
+
+ union content_msg_data msg_data;
+
+ node = html;
+ while (node) {
+ if (node->children) { /* children */
+ node = node->children;
+ } else if (node->next) { /* siblings */
+ node = node->next;
+ } else { /* ancestor siblings */
+ while (node && !node->next)
+ node = node->parent;
+ if (!node)
+ break;
+ node = node->next;
+ }
+ assert(node);
+
+ if (node->type != XML_ELEMENT_NODE)
+ continue;
+ if (strcmp((const char *) node->name, "link") == 0) {
+ /* rel=<space separated list, including 'icon'> */
+ if ((rel = (char *) xmlGetProp(node,
+ (const xmlChar *) "rel")) == NULL)
+ continue;
+ if (strcasestr(rel, "icon") == 0) {
+ xmlFree(rel);
+ continue;
+ }
+ LOG(("icon node found"));
+ if (strcasecmp(rel, "apple-touch-icon") == 0) {
+ xmlFree(rel);
+ continue;
+ }
+ xmlFree(rel);
+ if (( href = (char *) xmlGetProp(node,
+ (const xmlChar *) "href")) == NULL)
+ continue;
+ res = url_join(href, c->data.html.base_url,
+ &url);
+ xmlFree(href);
+ if (res != URL_FUNC_OK)
+ continue;
+ LOG(("most recent favicon '%s'", url));
+ if (url2 != NULL) {
+ free(url2);
+ url2 = NULL;
+ }
+ res = url_normalize(url, &url2);
+ if (res != URL_FUNC_OK) {
+ url2 = NULL;
+ if (res == URL_FUNC_NOMEM)
+ goto no_memory;
+ continue;
+ }
+ free(url);
+
+ }
+ }
+ if (url2 == NULL) {
+ if (url_join("/favicon.ico", c->data.html.base_url, &url2)
+ != URL_FUNC_OK)
+ return NULL;
+ }
+ LOG(("favicon %s", url2));
+ return url2;
+no_memory:
+ msg_data.error = messages_get("NoMemory");
+ /* content_broadcast(c, CONTENT_MSG_ERROR, msg_data); */
+ return false;
+}
+
+/**
+ * retrieve 1 favicon
+ * \param c content structure
+ * \param html xml node of html element
+ * \return true for success, false for error
+ */
+
+bool favicon_get_icon(struct content *c, xmlNode *html)
+{
+ char *url = favicon_get_icon_ref(c, html);
+ struct content *favcontent = NULL;
+ if (url == NULL)
+ return false;
+
+ favcontent = fetchcache(url, favicon_callback, (intptr_t) c, 0,
+ c->width, c->height, true, 0, 0, false, false);
+ free(url);
+ if (favcontent == NULL)
+ return false;
+
+ c->data.html.favicon = favcontent;
+
+ fetchcache_go(favcontent, c->url, favicon_callback, (intptr_t) c, 0,
+ c->width, c->height, 0, 0, false, c);
+
+ return true;
+}
+
+/**
+ * Callback for fetchcache() for linked favicon
+ */
+
+void favicon_callback(content_msg msg, struct content *icon,
+ intptr_t p1, intptr_t p2, union content_msg_data data)
+{
+ struct content *c = (struct content *) p1;
+ unsigned int i = p2;
+ switch (msg) {
+ case CONTENT_MSG_LOADING:
+ /* check that the favicon is really a correct image type */
+ if (!((icon->type == CONTENT_ICO) ||
+ (icon->type == CONTENT_PNG) ||
+ (icon->type == CONTENT_GIF))) {
+ c->data.html.favicon = 0;
+ LOG(("%s is not a favicon", icon->url));
+ content_add_error(c, "NotFavIco", 0);
+ html_set_status(c, messages_get("NotFavIco"));
+ content_broadcast(c, CONTENT_MSG_STATUS, data);
+ content_remove_user(icon,
+ favicon_callback,
+ (intptr_t) c, i);
+ if (!icon->user_list->next) {
+ /* we were the only user and we don't want this
+ * content, so stop it fetching and mark it as
+ * having an error so it gets removed from the
+ * cache next time content_clean() gets called
+ */
+ fetch_abort(icon->fetch);
+ icon->fetch = 0;
+ icon->status = CONTENT_STATUS_ERROR;
+ }
+ }
+ break;
+
+ case CONTENT_MSG_READY:
+ break;
+
+ case CONTENT_MSG_DONE:
+ LOG(("got favicon '%s'", icon->url));
+ break;
+
+ case CONTENT_MSG_LAUNCH:
+ /* Fall through */
+ case CONTENT_MSG_ERROR:
+ LOG(("favicon %s failed: %s", icon->url, data.error));
+ /* The favicon we were fetching may have been
+ * redirected, in that case, the object pointers
+ * will differ, so ensure that the object that's
+ * in error is still in use by us before invalidating
+ * the pointer */
+ if (c->data.html.favicon == icon) {
+ c->data.html.favicon = 0;
+ content_add_error(c, "?", 0);
+ }
+ break;
+
+ case CONTENT_MSG_STATUS:
+ html_set_status(c, icon->status_message);
+ content_broadcast(c, CONTENT_MSG_STATUS, data);
+ break;
+
+ case CONTENT_MSG_NEWPTR:
+ c->data.html.favicon = icon;
+ break;
+
+ case CONTENT_MSG_AUTH:
+ c->data.html.favicon = 0;
+ content_add_error(c, "?", 0);
+ break;
+
+ case CONTENT_MSG_SSL:
+ c->data.html.favicon = 0;
+ content_add_error(c, "?", 0);
+ break;
+ case CONTENT_MSG_REDRAW:
+ /* currently no support for favicon animations */
+ case CONTENT_MSG_REFRESH:
+ break;
+ case CONTENT_MSG_REFORMAT:
+ /* would be unusual :) */
+ break;
+ default:
+ assert(0);
+ }
+}
diff --git a/riscos/save_complete.h b/render/favicon.h
index 63db0e44d..30030101a 100644
--- a/riscos/save_complete.h
+++ b/render/favicon.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
@@ -16,17 +16,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/** \file
- * Save HTML document with dependencies (interface).
- */
-
-#ifndef _NETSURF_RISCOS_SAVE_COMPLETE_H_
-#define _NETSURF_RISCOS_SAVE_COMPLETE_H_
+#ifndef _NETSURF_RENDER_FAVICON_H_
+#define _NETSURF_RENDER_FAVICON_H_
-#include <stdbool.h>
-struct content;
+#include <libxml/tree.h>
+#include "content/content.h"
-void save_complete_init(void);
-bool save_complete(struct content *c, const char *path);
+bool favicon_get_icon(struct content *c, xmlNode *html);
#endif
diff --git a/render/html.c b/render/html.c
index 241d61350..8592ad6e2 100644
--- a/render/html.c
+++ b/render/html.c
@@ -37,6 +37,7 @@
#include "desktop/options.h"
#include "image/bitmap.h"
#include "render/box.h"
+#include "render/favicon.h"
#include "render/font.h"
#include "render/form.h"
#include "render/html.h"
@@ -74,7 +75,6 @@ static bool html_object_type_permitted(const content_type type,
static void html_object_refresh(void *p);
static void html_destroy_frameset(struct content_html_frames *frameset);
static void html_destroy_iframe(struct content_html_iframe *iframe);
-static void html_set_status(struct content *c, const char *extra);
#if ALWAYS_DUMP_FRAMESET
static void html_dump_frameset(struct content_html_frames *frame,
unsigned int depth);
@@ -307,6 +307,7 @@ encoding_change:
*
* - parsing to an XML tree is completed
* - stylesheets are fetched
+ * - favicon is retrieved
* - the XML tree is converted to a box tree and object fetches are started
* - the box tree is laid out
*
@@ -424,6 +425,9 @@ bool html_convert(struct content *c, int width, int height)
if (!html_find_stylesheets(c, html))
return false;
+ /* get icon */
+ favicon_get_icon(c, html);
+
/* Retrieve forms from parser */
c->data.html.forms = binding_get_forms(c->data.html.parser_binding);
for (f = c->data.html.forms; f != NULL; f = f->prev) {
@@ -792,7 +796,7 @@ bool html_meta_refresh(struct content *c, xmlNode *head)
* Uses STYLE and LINK elements inside and outside HEAD
*
* \param c content structure
- * \param head xml node of html element
+ * \param html xml node of html element
* \return true on success, false if an error occurred
*/
diff --git a/render/html.h b/render/html.h
index e18c33a2c..51abba3ba 100644
--- a/render/html.h
+++ b/render/html.h
@@ -133,6 +133,8 @@ struct content_html_data {
colour background_colour; /**< Document background colour. */
const struct font_functions *font_func;
+ struct content *favicon; /**< the favicon for the page */
+
/** Number of entries in stylesheet_content. */
unsigned int stylesheet_count;
/** Stylesheets. Each may be 0. */
@@ -189,6 +191,7 @@ void html_open(struct content *c, struct browser_window *bw,
struct content *page, unsigned int index, struct box *box,
struct object_params *params);
void html_close(struct content *c);
+void html_set_status(struct content *c, const char *extra);
/* in render/html_redraw.c */
bool html_redraw(struct content *c, int x, int y,
diff --git a/render/html_redraw.c b/render/html_redraw.c
index becf99fe4..2a5154035 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -41,6 +41,7 @@
#include "desktop/textinput.h"
#include "desktop/options.h"
#include "desktop/print.h"
+#include "desktop/search.h"
#include "desktop/scroll.h"
#include "image/bitmap.h"
#include "render/box.h"
@@ -880,12 +881,14 @@ bool text_redraw(const char *utf8_text, size_t utf8_len,
}
/* what about the current search operation, if any? */
- if (!highlighted && search_current_window ==
- current_redraw_browser->window &&
+ if (!highlighted && (current_redraw_browser->search_context
+ != NULL) &&
gui_search_term_highlighted(
current_redraw_browser->window,
offset, offset + len,
- &start_idx, &end_idx)) {
+ &start_idx, &end_idx,
+ current_redraw_browser->
+ search_context)) {
highlighted = true;
}
diff --git a/render/layout.c b/render/layout.c
index c83753195..3463210bc 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -4435,7 +4435,7 @@ void layout_calculate_descendant_bboxes(struct box *box)
{
struct box *child;
- if (box->width == UNKNOWN_WIDTH || box->height == AUTO /*||
+ if ((box->width == UNKNOWN_WIDTH) || (box->height == AUTO) /*||
box->width < 0 || box->height < 0*/) {
LOG(("%p has bad width or height", box));
/*while (box->parent)
diff --git a/render/textplain.c b/render/textplain.c
index 05d2fbe33..07f37610c 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -34,6 +34,7 @@
#include "desktop/gui.h"
#include "desktop/options.h"
#include "desktop/plotters.h"
+#include "desktop/search.h"
#include "desktop/selection.h"
#include "render/box.h"
#include "render/font.h"
@@ -437,11 +438,14 @@ bool textplain_redraw(struct content *c, int x, int y,
highlighted = true;
}
- if (!highlighted && search_current_window == bw->window) {
+ if (!highlighted && (bw->search_context
+ != NULL)) {
unsigned start_idx, end_idx;
- if (gui_search_term_highlighted(bw->window,
- tab_ofst, tab_ofst + 1,
- &start_idx, &end_idx))
+ if (gui_search_term_highlighted(
+ bw->window,
+ tab_ofst, tab_ofst + 1,
+ &start_idx, &end_idx,
+ bw->search_context))
highlighted = true;
}
diff --git a/riscos/gui.c b/riscos/gui.c
index 594488341..3fa95eaca 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -57,6 +57,7 @@
#include "desktop/gui.h"
#include "desktop/netsurf.h"
#include "desktop/options.h"
+#include "desktop/save_complete.h"
#include "desktop/tree.h"
#include "render/box.h"
#include "render/font.h"
@@ -76,7 +77,6 @@
#include "riscos/print.h"
#include "riscos/query.h"
#include "riscos/save.h"
-#include "riscos/save_complete.h"
#include "riscos/textselection.h"
#include "riscos/theme.h"
#include "riscos/treeview.h"
diff --git a/riscos/gui.h b/riscos/gui.h
index 2eaf7cb27..f7ddedd73 100644
--- a/riscos/gui.h
+++ b/riscos/gui.h
@@ -199,7 +199,7 @@ void ro_gui_debugwin_open(void);
/* in search.c */
void ro_gui_search_init(void);
-void ro_gui_search_prepare(struct gui_window *g);
+void ro_gui_search_prepare(struct browser_window *g);
bool ro_gui_search_prepare_menu(void);
/* in print.c */
diff --git a/riscos/menus.c b/riscos/menus.c
index ab286a1c9..3e6fe7615 100644
--- a/riscos/menus.c
+++ b/riscos/menus.c
@@ -2284,7 +2284,7 @@ void ro_gui_menu_prepare_action(wimp_w owner, menu_action action,
ro_gui_menu_set_entry_shaded(current_menu,
action, result);
if ((!result) && (windows)) {
- ro_gui_search_prepare(g);
+ ro_gui_search_prepare(g->bw);
}
if ((t) && (!t->editor) &&
(t->type == THEME_BROWSER_TOOLBAR))
diff --git a/riscos/save.c b/riscos/save.c
index 292c46194..44a2b1835 100644
--- a/riscos/save.c
+++ b/riscos/save.c
@@ -35,7 +35,9 @@
#include "oslib/osspriteop.h"
#include "oslib/wimp.h"
#include "oslib/wimpspriteop.h"
+#include "content/content.h"
#include "desktop/netsurf.h"
+#include "desktop/save_complete.h"
#include "desktop/save_text.h"
#include "desktop/selection.h"
#include "image/bitmap.h"
@@ -48,7 +50,6 @@
#include "riscos/options.h"
#include "riscos/query.h"
#include "riscos/save.h"
-#include "riscos/save_complete.h"
#include "riscos/save_draw.h"
#include "riscos/save_pdf.h"
#include "riscos/textselection.h"
@@ -988,6 +989,70 @@ void ro_gui_save_done(void)
gui_save_content = 0;
}
+/**
+* conducts the filesystem save appropriate to the gui
+* \param path save path
+* \param filename name of file to save
+* \param len data length
+* \param sourcedata pointer to data to save, NULL when all data in c
+* \param type content type
+* \return true for success
+*/
+
+bool save_complete_gui_save(const char *path, const char *filename, size_t len,
+ const char *sourcedata, content_type type)
+{
+ char *fullpath;
+ os_error *error;
+ int namelen = strlen(path) + strlen(filename) + 2;
+ int rotype;
+ fullpath = malloc(namelen);
+ if (fullpath == NULL) {
+ warn_user("NoMemory", 0);
+ return false;
+ }
+ snprintf(fullpath, namelen, "%s.%s", path, filename);
+ rotype = ro_content_filetype_from_type(type);
+ error = xosfile_save_stamped(fullpath, rotype, (byte *) sourcedata,
+ (byte *) sourcedata + len);
+ free(fullpath);
+ if (error) {
+ LOG(("xosfile_save_stamped: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ return false;
+ }
+ return true;
+}
+
+/**
+* wrapper for lib function htmlSaveFileFormat; front sets path from
+* path + filename in a filesystem-specific way
+*/
+
+int save_complete_htmlSaveFileFormat(const char *path, const char *filename,
+ xmlDocPtr cur, const char *encoding, int format)
+{
+ os_error *error;
+ int ret;
+ int len = strlen(path) + strlen(filename) + 2;
+ char *fullpath = malloc(len);
+ if (fullpath == NULL){
+ warn_user("NoMemory", 0);
+ return -1;
+ }
+ snprintf(fullpath, len, "%s.%s", path, filename);
+ ret = htmlSaveFileFormat(fullpath, cur, encoding, format);
+ error = xosfile_set_type(fullpath, 0xFAF);
+ if (error) {
+ LOG(("xosfile_save_stamped: 0x%x: %s",
+ error->errnum, error->errmess));
+ warn_user("SaveError", error->errmess);
+ return false;
+ }
+ free(fullpath);
+ return ret;
+}
/**
* Prepare an application directory and save_complete() to it.
diff --git a/riscos/search.c b/riscos/search.c
index 0dd502272..79f2a46af 100644
--- a/riscos/search.c
+++ b/riscos/search.c
@@ -31,6 +31,7 @@
#include "content/content.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
+#include "desktop/search.h"
#include "desktop/selection.h"
#include "render/box.h"
#include "render/html.h"
@@ -42,35 +43,19 @@
#include "utils/messages.h"
#include "utils/utils.h"
-#ifndef NOF_ELEMENTS
-#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
-#endif
-
-struct list_entry {
- unsigned start_idx; /* start position of match */
- unsigned end_idx; /* end of match */
-
- struct box *start_box; /* used only for html contents */
- struct box *end_box;
-
- struct selection *sel;
+#define RECENT_SEARCHES 8
- struct list_entry *prev;
- struct list_entry *next;
+struct search_static_data {
+ char *recent_searches[RECENT_SEARCHES];
+ bool search_insert;
+ struct browser_window *search_window;
+ search_flags_t flags;
+ char *string;
};
-struct gui_window *search_current_window = NULL;
-
-static char *search_string = NULL;
-static struct list_entry search_head = { 0, 0, NULL, NULL, NULL, NULL, NULL };
-static struct list_entry *search_found = &search_head;
-static struct list_entry *search_current = NULL;
-static struct content *search_content = NULL;
-static bool search_prev_case_sens = false;
+static struct search_static_data search_data =
+ {{NULL}, false, NULL, 0, NULL};
-#define RECENT_SEARCHES 8
-bool search_insert;
-static char *recent_search[RECENT_SEARCHES];
static wimp_MENU(RECENT_SEARCHES) menu_recent;
wimp_menu *recent_search_menu = (wimp_menu *)&menu_recent;
#define DEFAULT_FLAGS (wimp_ICON_TEXT | wimp_ICON_FILLED | \
@@ -78,26 +63,24 @@ wimp_menu *recent_search_menu = (wimp_menu *)&menu_recent;
(wimp_COLOUR_WHITE << wimp_ICON_BG_COLOUR_SHIFT))
-static void start_search(bool forwards);
-static void do_search(const char *string, int string_len, bool case_sens,
- bool forwards);
-static const char *find_pattern(const char *string, int s_len,
- const char *pattern, int p_len, bool case_sens,
- unsigned int *m_len);
-static bool find_occurrences_html(const char *pattern, int p_len,
- struct box *cur, bool case_sens);
-static bool find_occurrences_text(const char *pattern, int p_len,
- struct content *c, bool case_sens);
-static struct list_entry *add_entry(unsigned start_idx, unsigned end_idx);
-static void free_matches(void);
-static void show_all(bool all);
-static void show_status(bool found);
-
static void ro_gui_search_end(wimp_w w);
static bool ro_gui_search_next(wimp_w w);
static bool ro_gui_search_click(wimp_pointer *pointer);
static bool ro_gui_search_keypress(wimp_key *key);
-static void ro_gui_search_add_recent(const char *search);
+static search_flags_t ro_gui_search_update_flags(void);
+static void ro_gui_search_set_forward_state(bool active, void *p);
+static void ro_gui_search_set_back_state(bool active, void *p);
+static void ro_gui_search_set_status(bool found, void *p);
+static void ro_gui_search_set_hourglass(bool active, void *p);
+static void ro_gui_search_add_recent(const char *string, void *p);
+
+static struct search_callbacks ro_gui_search_callbacks = {
+ ro_gui_search_set_forward_state,
+ ro_gui_search_set_back_state,
+ ro_gui_search_set_status,
+ ro_gui_search_set_hourglass,
+ ro_gui_search_add_recent
+};
void ro_gui_search_init(void)
{
@@ -132,30 +115,66 @@ void ro_gui_search_init(void)
*/
bool ro_gui_search_next(wimp_w w)
{
- search_insert = true;
- start_search(true);
+ search_data.search_insert = true;
+ search_flags_t flags = SEARCH_FLAG_FORWARDS |
+ ro_gui_search_update_flags();
+ if (search_verify_new(search_data.search_window,
+ &ro_gui_search_callbacks, NULL))
+ search_step(search_data.search_window->search_context, flags,
+ ro_gui_get_icon_string(dialog_search,
+ ICON_SEARCH_TEXT));
return false;
}
bool ro_gui_search_click(wimp_pointer *pointer)
{
+ search_flags_t flags;
switch (pointer->i) {
case ICON_SEARCH_FIND_PREV:
- search_insert = true;
- start_search(false);
+ search_data.search_insert = true;
+ flags = ~SEARCH_FLAG_FORWARDS &
+ ro_gui_search_update_flags();
+ if (search_verify_new(search_data.search_window,
+ &ro_gui_search_callbacks, NULL))
+ search_step(search_data.search_window->
+ search_context, flags,
+ ro_gui_get_icon_string(
+ dialog_search,
+ ICON_SEARCH_TEXT));
return true;
case ICON_SEARCH_CASE_SENSITIVE:
- start_search(true);
+ flags = SEARCH_FLAG_FORWARDS |
+ ro_gui_search_update_flags();
+ if (search_verify_new(search_data.search_window,
+ &ro_gui_search_callbacks, NULL))
+ search_step(search_data.search_window->
+ search_context, flags,
+ ro_gui_get_icon_string(
+ dialog_search,
+ ICON_SEARCH_TEXT));
return true;
case ICON_SEARCH_SHOW_ALL:
- show_all(ro_gui_get_icon_selected_state(pointer->w,
- pointer->i));
+ if (search_data.search_window->search_context != NULL)
+ search_show_all(ro_gui_get_icon_selected_state(
+ pointer->w, pointer->i),
+ search_data.search_window->
+ search_context);
return true;
}
return false;
}
-void ro_gui_search_add_recent(const char *search)
+/**
+ * add search string to recent searches list
+ * front is at liberty how to implement the bare notification
+ * should normally store a strdup() of the string in
+ * search_global_data.recent[];
+ * core gives no guarantee of the integrity of the const char *
+ * \param string search pattern
+ * \param p the pointer sent to search_verify_new()
+ */
+
+void ro_gui_search_add_recent(const char *search, void *p)
{
char *tmp;
int i;
@@ -163,15 +182,15 @@ void ro_gui_search_add_recent(const char *search)
if ((search == NULL) || (search[0] == '\0'))
return;
- if (!search_insert) {
- free(recent_search[0]);
- recent_search[0] = strdup(search);
+ if (!search_data.search_insert) {
+ free(search_data.recent_searches[0]);
+ search_data.recent_searches[0] = strdup(search);
ro_gui_search_prepare_menu();
return;
}
- if ((recent_search[0] != NULL) &&
- (!strcmp(recent_search[0], search)))
+ if ((search_data.recent_searches[0] != NULL) &&
+ (!strcmp(search_data.recent_searches[0], search)))
return;
tmp = strdup(search);
@@ -179,11 +198,11 @@ void ro_gui_search_add_recent(const char *search)
warn_user("NoMemory", 0);
return;
}
- free(recent_search[RECENT_SEARCHES - 1]);
+ free(search_data.recent_searches[RECENT_SEARCHES - 1]);
for (i = RECENT_SEARCHES - 1; i > 0; i--)
- recent_search[i] = recent_search[i - 1];
- recent_search[0] = tmp;
- search_insert = false;
+ search_data.recent_searches[i] = search_data.recent_searches[i - 1];
+ search_data.recent_searches[0] = tmp;
+ search_data.search_insert = false;
ro_gui_set_icon_shaded_state(dialog_search, ICON_SEARCH_MENU, false);
ro_gui_search_prepare_menu();
@@ -196,7 +215,7 @@ bool ro_gui_search_prepare_menu(void)
int suggestions = 0;
for (i = 0; i < RECENT_SEARCHES; i++)
- if (recent_search[i] != NULL)
+ if (search_data.recent_searches[i] != NULL)
suggestions++;
if (suggestions == 0)
@@ -205,9 +224,9 @@ bool ro_gui_search_prepare_menu(void)
for (i = 0; i < suggestions; i++) {
recent_search_menu->entries[i].menu_flags &= ~wimp_MENU_LAST;
recent_search_menu->entries[i].data.indirected_text.text =
- recent_search[i];
+ search_data.recent_searches[i];
recent_search_menu->entries[i].data.indirected_text.size =
- strlen(recent_search[i]) + 1;
+ strlen(search_data.recent_searches[i]) + 1;
}
recent_search_menu->entries[suggestions - 1].menu_flags |=
wimp_MENU_LAST;
@@ -226,26 +245,29 @@ bool ro_gui_search_prepare_menu(void)
/**
* Open the search dialog
*
- * \param g the gui window to search
+ * \param bw the browser window to search
*/
-void ro_gui_search_prepare(struct gui_window *g)
+void ro_gui_search_prepare(struct browser_window *bw)
{
struct content *c;
- assert(g != NULL);
+ assert(bw != NULL);
- c = g->bw->current_content;
+ c = bw->current_content;
/* only handle html/textplain contents */
if ((!c) || (c->type != CONTENT_HTML &&
c->type != CONTENT_TEXTPLAIN))
return;
- /* if the search dialogue is reopened over a new window, we still
+ /* if the search dialogue is reopened over a new window, we may
need to cancel the previous search */
- ro_gui_search_end(dialog_search);
+ ro_gui_search_set_forward_state(true, bw);
+ ro_gui_search_set_back_state(true, bw);
+
+ search_create_context(bw, &ro_gui_search_callbacks, NULL);
- search_current_window = g;
+ search_data.search_window = bw;
ro_gui_set_icon_string(dialog_search, ICON_SEARCH_TEXT, "", true);
ro_gui_set_icon_selected_state(dialog_search,
@@ -253,14 +275,10 @@ void ro_gui_search_prepare(struct gui_window *g)
ro_gui_set_icon_selected_state(dialog_search,
ICON_SEARCH_SHOW_ALL, false);
- show_status(true);
- ro_gui_set_icon_shaded_state(dialog_search,
- ICON_SEARCH_FIND_PREV, true);
- ro_gui_set_icon_shaded_state(dialog_search,
- ICON_SEARCH_FIND_NEXT, true);
+ ro_gui_search_set_status(true, NULL);
ro_gui_wimp_event_memorise(dialog_search);
- search_insert = true;
+ search_data.search_insert = true;
}
/**
@@ -272,6 +290,7 @@ void ro_gui_search_prepare(struct gui_window *g)
bool ro_gui_search_keypress(wimp_key *key)
{
bool state;
+ search_flags_t flags;
switch (key->c) {
case 1: { /* ctrl a */
@@ -279,7 +298,9 @@ bool ro_gui_search_keypress(wimp_key *key)
ICON_SEARCH_SHOW_ALL);
ro_gui_set_icon_selected_state(key->w,
ICON_SEARCH_SHOW_ALL, sel);
- show_all(sel);
+ if (search_data.search_window->search_context != NULL)
+ search_show_all(sel,
+ search_data.search_window->search_context);
}
break;
case 9: /* ctrl i */
@@ -287,27 +308,79 @@ bool ro_gui_search_keypress(wimp_key *key)
ICON_SEARCH_CASE_SENSITIVE);
ro_gui_set_icon_selected_state(dialog_search,
ICON_SEARCH_CASE_SENSITIVE, !state);
- start_search(true);
+ flags = SEARCH_FLAG_FORWARDS |
+ ro_gui_search_update_flags();
+ if (search_verify_new(search_data.search_window,
+ &ro_gui_search_callbacks, NULL))
+ search_step(search_data.search_window->
+ search_context, flags,
+ ro_gui_get_icon_string(
+ dialog_search,
+ ICON_SEARCH_TEXT));
return true;
case IS_WIMP_KEY | wimp_KEY_UP:
- search_insert = true;
- start_search(false);
+ search_data.search_insert = true;
+ flags = ~SEARCH_FLAG_FORWARDS &
+ ro_gui_search_update_flags();
+ if (search_verify_new(search_data.search_window,
+ &ro_gui_search_callbacks, NULL))
+ search_step(search_data.search_window->
+ search_context, flags,
+ ro_gui_get_icon_string(
+ dialog_search,
+ ICON_SEARCH_TEXT));
return true;
case IS_WIMP_KEY | wimp_KEY_DOWN:
- search_insert = true;
- start_search(true);
+ search_data.search_insert = true;
+ flags = SEARCH_FLAG_FORWARDS |
+ ro_gui_search_update_flags();
+ if (search_verify_new(search_data.search_window,
+ &ro_gui_search_callbacks, NULL))
+ search_step(search_data.search_window->
+ search_context, flags,
+ ro_gui_get_icon_string(
+ dialog_search,
+ ICON_SEARCH_TEXT));
return true;
default:
if (key->c == 21) {
/* ctrl+u means the user's starting
* a new search */
- search_insert = true;
+ if (search_data.search_window->search_context != NULL)
+ search_destroy_context(
+ search_data.
+ search_window->
+ search_context);
+ ro_gui_search_set_forward_state(true,
+ search_data.search_window);
+ ro_gui_search_set_back_state(true,
+ search_data.search_window);
+ search_data.search_insert = true;
}
if (key->c == 8 || /* backspace */
key->c == 21 || /* ctrl u */
(key->c >= 0x20 && key->c <= 0x7f)) {
- start_search(true);
+ flags = SEARCH_FLAG_FORWARDS |
+ ro_gui_search_update_flags();
+ if (search_data.search_window->search_context
+ != NULL)
+ search_destroy_context(
+ search_data.
+ search_window->
+ search_context);
+ ro_gui_search_set_forward_state(true,
+ search_data.search_window);
+ ro_gui_search_set_back_state(true,
+ search_data.search_window);
+ if (search_verify_new(search_data.search_window,
+ &ro_gui_search_callbacks,
+ NULL))
+ search_step(search_data.search_window->
+ search_context, flags,
+ ro_gui_get_icon_string(
+ dialog_search,
+ ICON_SEARCH_TEXT));
return true;
}
break;
@@ -317,564 +390,80 @@ bool ro_gui_search_keypress(wimp_key *key)
}
/**
- * Begins/continues the search process
- * Note that this may be called many times for a single search.
- *
- * \param forwards search forwards from start/current position
- */
-
-void start_search(bool forwards)
-{
- int string_len;
- const char *string;
- int i = 0;
-
- string = ro_gui_get_icon_string(dialog_search, ICON_SEARCH_TEXT);
- assert(string);
-
- ro_gui_search_add_recent(string);
-
- string_len = strlen(string);
- for(i = 0; i < string_len; i++)
- if (string[i] != '#' && string[i] != '*') break;
- if (i >= string_len) {
- free_matches();
- show_status(true);
- ro_gui_set_icon_shaded_state(dialog_search,
- ICON_SEARCH_FIND_PREV, true);
- ro_gui_set_icon_shaded_state(dialog_search,
- ICON_SEARCH_FIND_NEXT, true);
- gui_window_set_scroll(search_current_window, 0, 0);
- return;
- }
-
- do_search(string, string_len,
- ro_gui_get_icon_selected_state(dialog_search,
- ICON_SEARCH_CASE_SENSITIVE),
- forwards);
-}
-
-/**
- * Ends the search process, invalidating all global state and
- * freeing the list of found boxes
- *
- * \param w the search window handle (not used)
+ * Ends the search
+ * \param w the search window handle (not used)
*/
void ro_gui_search_end(wimp_w w)
{
- search_current_window = 0;
-
- if (search_string) {
- ro_gui_search_add_recent(search_string);
- free(search_string);
- }
- search_string = 0;
-
- free_matches();
-
- search_current = 0;
-
- search_content = 0;
-
- search_prev_case_sens = false;
-}
-
-
-/**
- * Release the memory used by the list of matches,
- * deleting selection objects too
- */
-
-void free_matches(void)
-{
- struct list_entry *a = search_found->next;
- struct list_entry *b;
-
- /* empty the list before clearing and deleting the
- selections because the the clearing updates the
- screen immediately, causing nested accesses to the list */
-
- search_found->prev = 0;
- search_found->next = 0;
-
- for (; a; a = b) {
- b = a->next;
- if (a->sel) {
- selection_clear(a->sel, true);
- selection_destroy(a->sel);
- }
- free(a);
- }
-}
-
-
-/**
- * Search for a string in the box tree
- *
- * \param string the string to search for
- * \param string_len length of search string
- * \param case_sens whether to perform a case sensitive search
- * \param forwards direction to search in
- */
-void do_search(const char *string, int string_len, bool case_sens,
- bool forwards)
-{
- struct rect bounds;
- struct content *c;
- struct box *box;
- bool new = false;
-
- if (!search_current_window)
- return;
-
- c = search_current_window->bw->current_content;
-
- /* only handle html contents */
- if ((!c) || (c->type != CONTENT_HTML &&
- c->type != CONTENT_TEXTPLAIN))
- return;
-
- box = c->data.html.layout;
-
- if (!box)
- return;
-
-// LOG(("do_search '%s' - '%s' (%p, %p) %p (%d, %d) %d",
-// search_string, string, search_content, c, search_found->next,
-// search_prev_case_sens, case_sens, forwards));
-
- /* check if we need to start a new search or continue an old one */
- if (!search_string || c != search_content || !search_found->next ||
- search_prev_case_sens != case_sens ||
- (case_sens && strcmp(string, search_string) != 0) ||
- (!case_sens && strcasecmp(string, search_string) != 0)) {
- bool res;
-
- if (search_string)
- free(search_string);
- search_current = 0;
- free_matches();
-
- search_string = malloc(string_len + 1);
- if (search_string) {
- memcpy(search_string, string, string_len);
- search_string[string_len] = '\0';
- }
-
- xhourglass_on();
-
- if (c->type == CONTENT_HTML)
- res = find_occurrences_html(string, string_len,
- box, case_sens);
- else {
- assert(c->type == CONTENT_TEXTPLAIN);
- res = find_occurrences_text(string, string_len,
- c, case_sens);
- }
-
- if (!res) {
- free_matches();
- xhourglass_off();
- return;
- }
- xhourglass_off();
-
- new = true;
- search_content = c;
- search_prev_case_sens = case_sens;
- }
-
-// LOG(("%d %p %p (%p, %p)", new, search_found->next, search_current, search_current->prev, search_current->next));
-
- if (new) {
- /* new search, beginning at the top of the page */
- search_current = search_found->next;
- }
- else if (search_current) {
- /* continued search in the direction specified */
- if (forwards) {
- if (search_current->next)
- search_current = search_current->next;
- }
- else {
- if (search_current->prev)
- search_current = search_current->prev;
- }
- }
-
- show_status(search_current != NULL);
- show_all(ro_gui_get_icon_selected_state(dialog_search,
- ICON_SEARCH_SHOW_ALL));
-
- ro_gui_set_icon_shaded_state(dialog_search, ICON_SEARCH_FIND_PREV,
- !search_current || !search_current->prev);
- ro_gui_set_icon_shaded_state(dialog_search, ICON_SEARCH_FIND_NEXT,
- !search_current || !search_current->next);
-
- if (!search_current)
- return;
-
- switch (c->type) {
- case CONTENT_HTML:
- /* get box position and jump to it */
- box_coords(search_current->start_box,
- &bounds.x0, &bounds.y0);
- /* \todo: move x0 in by correct idx */
- box_coords(search_current->end_box,
- &bounds.x1, &bounds.y1);
- /* \todo: move x1 in by correct idx */
- bounds.x1 += search_current->end_box->width;
- bounds.y1 += search_current->end_box->height;
- break;
-
- default:
- assert(c->type == CONTENT_TEXTPLAIN);
- textplain_coords_from_range(c,
- search_current->start_idx,
- search_current->end_idx, &bounds);
- break;
- }
-
- gui_window_scroll_visible(search_current_window,
- bounds.x0, bounds.y0, bounds.x1, bounds.y1);
-}
-
-
-/**
- * Find the first occurrence of 'match' in 'string' and return its index
- *
- * /param string the string to be searched (unterminated)
- * /param s_len length of the string to be searched
- * /param pattern the pattern for which we are searching (unterminated)
- * /param p_len length of pattern
- * /param case_sens true iff case sensitive match required
- * /param m_len accepts length of match in bytes
- * /return pointer to first match, NULL if none
- */
-
-const char *find_pattern(const char *string, int s_len, const char *pattern,
- int p_len, bool case_sens, unsigned int *m_len)
-{
- struct { const char *ss, *s, *p; bool first; } context[16];
- const char *ep = pattern + p_len;
- const char *es = string + s_len;
- const char *p = pattern - 1; /* a virtual '*' before the pattern */
- const char *ss = string;
- const char *s = string;
- bool first = true;
- int top = 0;
-
- while (p < ep) {
- bool matches;
- if (p < pattern || *p == '*') {
- char ch;
-
- /* skip any further asterisks; one is the same as many */
- do p++; while (p < ep && *p == '*');
-
- /* if we're at the end of the pattern, yes, it matches */
- if (p >= ep) break;
-
- /* anything matches a # so continue matching from
- here, and stack a context that will try to match
- the wildcard against the next character */
-
- ch = *p;
- if (ch != '#') {
- /* scan forwards until we find a match for this char */
- if (!case_sens) ch = toupper(ch);
- while (s < es) {
- if (case_sens) {
- if (*s == ch) break;
- } else if (toupper(*s) == ch)
- break;
- s++;
- }
- }
-
- if (s < es) {
- /* remember where we are in case the match fails;
- we can then resume */
- if (top < (int)NOF_ELEMENTS(context)) {
- context[top].ss = ss;
- context[top].s = s + 1;
- context[top].p = p - 1; /* ptr to last asterisk */
- context[top].first = first;
- top++;
- }
-
- if (first) {
- ss = s; /* remember first non-'*' char */
- first = false;
- }
-
- matches = true;
- }
- else
- matches = false;
- }
- else if (s < es) {
- char ch = *p;
- if (ch == '#')
- matches = true;
- else {
- if (case_sens)
- matches = (*s == ch);
- else
- matches = (toupper(*s) == toupper(ch));
- }
- if (matches && first) {
- ss = s; /* remember first non-'*' char */
- first = false;
- }
- }
- else
- matches = false;
-
- if (matches) {
- p++; s++;
- }
- else {
- /* doesn't match, resume with stacked context if we have one */
- if (--top < 0) return NULL; /* no match, give up */
-
- ss = context[top].ss;
- s = context[top].s;
- p = context[top].p;
- first = context[top].first;
- }
- }
-
- /* end of pattern reached */
- *m_len = max(s - ss, 1);
- return ss;
+ if (search_data.search_window->search_context != NULL)
+ search_destroy_context(search_data.search_window->
+ search_context);
+ ro_gui_search_set_forward_state(true, search_data.search_window);
+ ro_gui_search_set_back_state(true, search_data.search_window);
}
-
/**
- * Finds all occurrences of a given string in the html box tree
- *
- * \param pattern the string pattern to search for
- * \param p_len pattern length
- * \param cur pointer to the current box
- * \param case_sens whether to perform a case sensitive search
- * \return true on success, false on memory allocation failure
- */
-bool find_occurrences_html(const char *pattern, int p_len, struct box *cur,
- bool case_sens)
-{
- struct box *a;
-
- /* ignore this box, if there's no visible text */
- if (!cur->object && cur->text) {
- const char *text = cur->text;
- unsigned length = cur->length;
-
- while (length > 0) {
- struct list_entry *entry;
- unsigned match_length;
- unsigned match_offset;
- const char *new_text;
- const char *pos = find_pattern(text, length,
- pattern, p_len, case_sens,
- &match_length);
- if (!pos) break;
-
- /* found string in box => add to list */
- match_offset = pos - cur->text;
-
- entry = add_entry(cur->byte_offset + match_offset,
- cur->byte_offset +
- match_offset +
- match_length);
- if (!entry)
- return false;
-
- entry->start_box = cur;
- entry->end_box = cur;
-
- new_text = pos + match_length;
- length -= (new_text - text);
- text = new_text;
- }
- }
-
- /* and recurse */
- for (a = cur->children; a; a = a->next) {
- if (!find_occurrences_html(pattern, p_len, a, case_sens))
- return false;
- }
-
- return true;
-}
+* Change the displayed search status.
+* \param found search pattern matched in text
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
-
-/**
- * Finds all occurrences of a given string in a textplain content
- *
- * \param pattern the string pattern to search for
- * \param p_len pattern length
- * \param c the content to be searched
- * \param case_sens wheteher to perform a case sensitive search
- * \return true on success, false on memory allocation failure
- */
-
-bool find_occurrences_text(const char *pattern, int p_len,
- struct content *c, bool case_sens)
+void ro_gui_search_set_status(bool found, void *p)
{
- int nlines = textplain_line_count(c);
- int line;
-
- for(line = 0; line < nlines; line++) {
- size_t offset, length;
- const char *text = textplain_get_line(c, line,
- &offset, &length);
- if (text) {
- while (length > 0) {
- struct list_entry *entry;
- unsigned match_length;
- size_t start_idx;
- const char *new_text;
- const char *pos = find_pattern(text, length,
- pattern, p_len, case_sens,
- &match_length);
- if (!pos) break;
-
- /* found string in line => add to list */
- start_idx = offset + (pos - text);
- entry = add_entry(start_idx, start_idx +
- match_length);
- if (!entry)
- return false;
-
- new_text = pos + match_length;
- offset += (new_text - text);
- length -= (new_text - text);
- text = new_text;
- }
- }
- }
-
- return true;
+ ro_gui_set_icon_string(dialog_search, ICON_SEARCH_STATUS, found ? "" :
+ messages_get("NotFound"), true);
}
-
/**
- * Add a new entry to the list of matches
- *
- * \param start_idx offset of match start within textual representation
- * \param end_idx offset of match end
- * \return pointer to added entry, NULL iff failed
- */
+* display hourglass while searching
+* \param active start/stop indicator
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
-struct list_entry *add_entry(unsigned start_idx, unsigned end_idx)
+void ro_gui_search_set_hourglass(bool active, void *p)
{
- struct list_entry *entry;
-
- /* found string in box => add to list */
- entry = calloc(1, sizeof(*entry));
- if (!entry) {
- warn_user("NoMemory", 0);
- return NULL;
- }
-
- entry->start_idx = start_idx;
- entry->end_idx = end_idx;
- entry->sel = NULL;
+ if (active)
+ xhourglass_on();
- entry->next = 0;
- entry->prev = search_found->prev;
- if (!search_found->prev)
- search_found->next = entry;
else
- search_found->prev->next = entry;
- search_found->prev = entry;
-
- return entry;
+ xhourglass_off();
}
-
/**
- * Determines whether any portion of the given text box should be
- * selected because it matches the current search string.
- *
- * \param g gui window
- * \param start_offset byte offset within text of string to be checked
- * \param end_offset byte offset within text
- * \param start_idx byte offset within string of highlight start
- * \param end_idx byte offset of highlight end
- * \return true iff part of the box should be highlighted
- */
+* activate search forwards button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
-bool gui_search_term_highlighted(struct gui_window *g,
- unsigned start_offset, unsigned end_offset,
- unsigned *start_idx, unsigned *end_idx)
+void ro_gui_search_set_forward_state(bool active, void *p)
{
- if (g == search_current_window) {
- struct list_entry *a;
- for(a = search_found->next; a; a = a->next)
- if (a->sel && selection_defined(a->sel) &&
- selection_highlighted(a->sel,
- start_offset, end_offset,
- start_idx, end_idx))
- return true;
- }
-
- return false;
+ ro_gui_set_icon_shaded_state(dialog_search, ICON_SEARCH_FIND_NEXT,
+ !active);
}
-
/**
- * Specifies whether all matches or just the current match should
- * be highlighted in the search text.
- */
+* activate search forwards button in gui
+* \param active activate/inactivate
+* \param p the pointer sent to search_verify_new() / search_create_context()
+*/
-void show_all(bool all)
+void ro_gui_search_set_back_state(bool active, void *p)
{
- struct list_entry *a;
-
- for (a = search_found->next; a; a = a->next) {
- bool add = true;
- if (!all && a != search_current) {
- add = false;
- if (a->sel) {
- selection_clear(a->sel, true);
- selection_destroy(a->sel);
- a->sel = NULL;
- }
- }
- if (add && !a->sel) {
- a->sel = selection_create(search_current_window->bw);
- if (a->sel) {
- struct content *c = search_current_window->bw->current_content;
- switch (c->type) {
- case CONTENT_HTML:
- selection_init(a->sel,
- c->data.html.layout);
- break;
- default:
- assert(c->type ==
- CONTENT_TEXTPLAIN);
- selection_init(a->sel, NULL);
- break;
- }
- selection_set_start(a->sel, a->start_idx);
- selection_set_end(a->sel, a->end_idx);
- }
- }
- }
+ ro_gui_set_icon_shaded_state(dialog_search, ICON_SEARCH_FIND_PREV,
+ !active);
}
-
/**
- * Change the displayed search status.
- *
- * \param found search pattern matched in text
- */
-
-void show_status(bool found)
+* retrieve state of 'case sensitive', 'show all' checks in gui
+*/
+search_flags_t ro_gui_search_update_flags(void)
{
- ro_gui_set_icon_string(dialog_search, ICON_SEARCH_STATUS,
- found ? "" : messages_get("NotFound"), true);
+ search_flags_t flags;
+ flags = 0 | (ro_gui_get_icon_selected_state(dialog_search,
+ ICON_SEARCH_CASE_SENSITIVE) ?
+ SEARCH_FLAG_CASE_SENSITIVE : 0) |
+ (ro_gui_get_icon_selected_state(dialog_search,
+ ICON_SEARCH_SHOW_ALL) ? SEARCH_FLAG_SHOWALL : 0);
+ return flags;
}
diff --git a/riscos/searchweb.c b/riscos/searchweb.c
new file mode 100644
index 000000000..14246d228
--- /dev/null
+++ b/riscos/searchweb.c
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf 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; version 2 of the License.
+ *
+ * NetSurf 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, see <http://www.gnu.org/licenses/>.
+ */
+
diff --git a/riscos/window.c b/riscos/window.c
index 764a014ed..effb4dac6 100644
--- a/riscos/window.c
+++ b/riscos/window.c
@@ -1104,6 +1104,21 @@ void gui_window_stop_throbber(struct gui_window *g)
}
}
+/**
+ * set favicon
+ */
+void gui_window_set_icon(struct gui_window *g, struct content *icon)
+{
+}
+
+/**
+* set gui display of a retrieved favicon representing the search provider
+* \param ico may be NULL for local calls; then access current cache from
+* search_web_ico()
+*/
+void gui_window_set_search_ico(struct content *ico)
+{
+}
/**
* Place the caret in a browser window.
diff --git a/utils/config.h b/utils/config.h
index e184c6964..c86770b6e 100644
--- a/utils/config.h
+++ b/utils/config.h
@@ -70,6 +70,11 @@ char *strchrnul(const char *s, int c);
#define WITH_MMAP
#endif
+#if defined(gtk)
+ #define WITH_THEME_INSTALL
+#endif
+
+
/* Configuration sanity checks: */
#if defined(WITH_NS_SVG) && defined(WITH_RSVG)
#error Cannot build WITH_NS_SVG and WITH_RSVG both enabled
diff --git a/utils/container.c b/utils/container.c
index 900eac6c3..04d8da8d0 100644
--- a/utils/container.c
+++ b/utils/container.c
@@ -19,26 +19,34 @@
/* To build a stand-alone command-line utility to create and dismantal
* these theme files, build this thusly:
*
- * gcc -I../../ -DNSTHEME -o themetool container.c
+ * gcc -I../ -DNSTHEME -o themetool container.c
*
+ * then for instance to create a theme file called mythemefilename
+ * ./themetool --verbose --create -n"My theme name" mythemefilename\
+ * --author "Myname" /path/to/directory/containing/theme/files/
*/
/** \file
* Container format handling for themes etc. */
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
+#include <sys/stat.h>
#include <arpa/inet.h>
-#include "utils/container.h"
#include "utils/config.h"
+#include "utils/container.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/utils.h"
#ifdef WITH_MMAP
#include <sys/mman.h>
#endif
struct container_dirent {
- unsigned char filename[16];
+ unsigned char filename[64];
u_int32_t startoffset;
u_int32_t len;
u_int32_t flags1;
@@ -85,7 +93,8 @@ static void container_add_to_dir(struct container_ctx *ctx,
sizeof(struct container_dirent));
strncpy((char *)ctx->directory[ctx->entries - 1].filename,
- (char *)entryname, 16);
+ (char *)entryname, sizeof(ctx->directory[
+ ctx->entries - 1].filename));
ctx->directory[ctx->entries - 1].startoffset = offset;
ctx->directory[ctx->entries - 1].len = length;
ctx->directory[ctx->entries - 1].flags1 = 0;
@@ -94,6 +103,7 @@ static void container_add_to_dir(struct container_ctx *ctx,
struct container_ctx *container_open(const char *filename)
{
+ size_t val;
struct container_ctx *ctx = calloc(sizeof(struct container_ctx), 1);
ctx->fh = fopen(filename, "rb");
@@ -109,16 +119,26 @@ struct container_ctx *container_open(const char *filename)
*/
ctx->processed = false;
- fread(&ctx->header.magic, 4, 1, ctx->fh);
+ val = fread(&ctx->header.magic, 4, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty read magic"));
ctx->header.magic = ntohl(ctx->header.magic);
- fread(&ctx->header.parser, 4, 1, ctx->fh);
+ val = fread(&ctx->header.parser, 4, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty read parser"));
ctx->header.parser = ntohl(ctx->header.parser);
- fread(ctx->header.name, 32, 1, ctx->fh);
- fread(ctx->header.author, 64, 1, ctx->fh);
+ val = fread(ctx->header.name, 32, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty read name"));
+ val = fread(ctx->header.author, 64, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty read author"));
- fread(&ctx->header.diroffset, 4, 1, ctx->fh);
+ val = fread(&ctx->header.diroffset, 4, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty read diroffset"));
ctx->header.diroffset = ntohl(ctx->header.diroffset);
if (ctx->header.magic != 0x4e53544d || ctx->header.parser != 3) {
@@ -132,7 +152,8 @@ struct container_ctx *container_open(const char *filename)
static void container_process(struct container_ctx *ctx)
{
- unsigned char filename[16];
+ size_t val;
+ unsigned char filename[64];
u_int32_t start, len, flags1, flags2;
#ifdef WITH_MMAP
@@ -141,14 +162,19 @@ static void container_process(struct container_ctx *ctx)
#else
ctx->data = malloc(ctx->header.diroffset);
fseek(ctx->fh, 0, SEEK_SET);
- fread(ctx->data, ctx->header.diroffset, 1, ctx->fh);
+ val = fread(ctx->data, ctx->header.diroffset, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty read diroffset"));
#endif
fseek(ctx->fh, ctx->header.diroffset, SEEK_SET);
/* now work through the directory structure taking it apart into
* our structure */
-#define BEREAD(x) do { fread(&(x), 4, 1, ctx->fh);(x) = ntohl((x)); } while (0)
+#define BEREAD(x) do { val = fread(&(x), 4, 1, ctx->fh); if (val == 0)\
+ LOG(("empty read"));(x) = ntohl((x)); } while (0)
do {
- fread(filename, 16, 1, ctx->fh);
+ val = fread(filename, 64, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty read filename"));
BEREAD(start);
BEREAD(len);
BEREAD(flags1);
@@ -164,7 +190,7 @@ static const struct container_dirent *container_lookup(
struct container_ctx *ctx,
const unsigned char *entryname)
{
- int i;
+ unsigned int i;
for (i = 1; i <= ctx->entries; i++) {
struct container_dirent *e = ctx->directory + i - 1;
@@ -227,12 +253,16 @@ const unsigned char *container_get_author(struct container_ctx *ctx)
static void container_write_dir(struct container_ctx *ctx)
{
- int i;
+ size_t val;
+ unsigned int i;
u_int32_t tmp;
-#define BEWRITE(x) do {tmp = htonl((x)); fwrite(&tmp, 4, 1, ctx->fh);} while(0)
+#define BEWRITE(x) do {tmp = htonl((x)); val = fwrite(&tmp, 4, 1, ctx->fh);\
+ if (val == 0) LOG(("empty write")); } while(0)
for (i = 1; i <= ctx->entries; i++) {
struct container_dirent *e = ctx->directory + i - 1;
- fwrite(e->filename, 16, 1, ctx->fh);
+ val = fwrite(e->filename, 64, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty write filename"));
BEWRITE(e->startoffset);
BEWRITE(e->len);
BEWRITE(e->flags1);
@@ -241,13 +271,16 @@ static void container_write_dir(struct container_ctx *ctx)
#undef BEWRITE
/* empty entry signifies end of directory */
tmp = 0;
- fwrite(&tmp, 4, 8, ctx->fh);
+ val = fwrite(&tmp, 4, 8, ctx->fh);
+ if (val == 0)
+ LOG(("empty write end"));
}
struct container_ctx *container_create(const char *filename,
const unsigned char *name,
const unsigned char *author)
{
+ size_t val;
struct container_ctx *ctx = calloc(sizeof(struct container_ctx), 1);
ctx->fh = fopen(filename, "wb");
@@ -264,10 +297,18 @@ struct container_ctx *container_create(const char *filename,
strncpy((char *)ctx->header.name, (char *)name, 32);
strncpy((char *)ctx->header.author, (char *)author, 64);
- fwrite("NSTM", 4, 1, ctx->fh);
- fwrite(&ctx->header.parser, 4, 1, ctx->fh);
- fwrite(ctx->header.name, 32, 1, ctx->fh);
- fwrite(ctx->header.author, 64, 1, ctx->fh);
+ val = fwrite("NSTM", 4, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty write NSTM"));
+ val = fwrite(&ctx->header.parser, 4, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty write parser"));
+ val = fwrite(ctx->header.name, 32, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty write name"));
+ val = fwrite(ctx->header.author, 64, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty write author"));
ctx->header.diroffset = 108;
@@ -284,14 +325,17 @@ void container_add(struct container_ctx *ctx, const unsigned char *entryname,
const unsigned char *data,
const u_int32_t datalen)
{
+ size_t val;
container_add_to_dir(ctx, entryname, ftell(ctx->fh), datalen);
- fwrite(data, datalen, 1, ctx->fh);
+ val = fwrite(data, datalen, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty write add file"));
}
void container_close(struct container_ctx *ctx)
{
if (ctx->creating == true) {
- size_t flen, nflen;
+ size_t flen, nflen, val;
/* discover where the directory's going to go. */
flen = container_filelen(ctx->fh);
@@ -300,7 +344,9 @@ void container_close(struct container_ctx *ctx)
/* write this location to the header */
fseek(ctx->fh, 104, SEEK_SET);
nflen = htonl(flen);
- fwrite(&nflen, 4, 1, ctx->fh);
+ val = fwrite(&nflen, 4, 1, ctx->fh);
+ if (val == 0)
+ LOG(("empty write directory location"));
/* seek to where the directory will be, and write it */
fseek(ctx->fh, flen, SEEK_SET);
@@ -318,6 +364,85 @@ void container_close(struct container_ctx *ctx)
free(ctx);
}
+#ifdef WITH_THEME_INSTALL
+
+/**
+ * install theme from container
+ * \param themefile a file containing the containerized theme
+ * \param dirbasename a directory basename including trailing path sep; the
+ * full path of the theme is then a subdirectory of that
+ * caller owns reference to returned string, NULL for error
+ */
+
+char *container_extract_theme(const char *themefile, const char *dirbasename)
+{
+ struct stat statbuf;
+ struct container_ctx *cctx;
+ FILE *fh;
+ size_t val;
+ const unsigned char *e, *d;
+ char *themename, *dirname;
+ char path[PATH_MAX];
+ int state = 0;
+ unsigned int i;
+ u_int32_t flen;
+
+ cctx = container_open(themefile);
+ if (cctx == NULL) {
+ warn_user("FileOpenError", themefile);
+ return NULL;
+ }
+ themename = strdup((const char *)container_get_name(cctx));
+ if (themename == NULL) {
+ warn_user("NoMemory", 0);
+ container_close(cctx);
+ return NULL;
+ }
+ LOG(("theme name: %s", themename));
+ LOG(("theme author: %s", container_get_author(cctx)));
+
+ dirname = malloc(strlen(dirbasename) + strlen(themename) + 2);
+ if (dirname == NULL) {
+ warn_user(messages_get("NoMemory"), 0);
+ free(themename);
+ container_close(cctx);
+ return NULL;
+ }
+ strcpy(dirname, dirbasename);
+ strcat(dirname, themename);
+ if (stat(dirname, &statbuf) != -1) {
+ warn_user("DirectoryError", dirname);
+ container_close(cctx);
+ free(dirname);
+ free(themename);
+ return NULL;
+ }
+ mkdir(dirname, 00777);
+
+ for (e = container_iterate(cctx, &state), i = 0; i < cctx->entries;
+ e = container_iterate(cctx, &state), i++) {
+ LOG(("extracting %s", e));
+ snprintf(path, PATH_MAX, "%s/%s", dirname, e);
+ fh = fopen(path, "wb");
+ if (fh == NULL) {
+ warn_user("FileOpenError", (char *)e);
+ } else {
+ d = container_get(cctx, e, &flen);
+ val = fwrite(d, flen, 1, fh);
+ if (val == 0)
+ LOG(("empty write"));
+ fclose(fh);
+ }
+ }
+ LOG(("theme container unpacked"));
+ container_close(cctx);
+ free(dirname);
+ return themename;
+
+}
+
+#endif
+
#ifdef TEST_RIG
int main(int argc, char *argv[])
{
@@ -355,7 +480,6 @@ int main(int argc, char *argv[])
#include <getopt.h>
#include <dirent.h>
#include <errno.h>
-#include <sys/stat.h>
#include <unistd.h>
static bool verbose = false;
@@ -403,7 +527,8 @@ static void extract_theme(const char *themefile, const char *dirname)
printf("theme author: %s\n", container_get_author(cctx));
}
- while ( (e = container_iterate(cctx, &state)) ) {
+ for (e = container_iterate(cctx, &state), i = 0; i < cctx->entries;
+ e = container_iterate(cctx, &state), i++) {
if (verbose == true)
printf("extracting %s\n", e);
snprintf(path, PATH_MAX, "%s/%s", dirname, e);
@@ -450,9 +575,9 @@ static void create_theme(const char *themefile, const char *dirname,
/* not the metadirs, so we want to process this. */
if (verbose == true)
printf("adding %s\n", e->d_name);
- if (strlen(e->d_name) > 15) {
+ if (strlen(e->d_name) > 63) {
fprintf(stderr,
- "warning: name truncated to 15 characters.\n");
+ "warning: name truncated to length 63.\n");
}
snprintf(path, PATH_MAX, "%s/%s", dirname, e->d_name);
diff --git a/utils/container.h b/utils/container.h
index 46537aaa6..de880ecd5 100644
--- a/utils/container.h
+++ b/utils/container.h
@@ -47,4 +47,7 @@ void container_add(struct container_ctx *ctx, const unsigned char *entryname,
/* common interface */
void container_close(struct container_ctx *ctx);
+#ifdef WITH_THEME_INSTALL
+char *container_extract_theme(const char *themefile, const char *dirbasename);
+#endif
#endif /* __CONTAINER_H__ */
diff --git a/utils/utils.c b/utils/utils.c
index ae58222b9..c8cfcb410 100644
--- a/utils/utils.c
+++ b/utils/utils.c
@@ -62,6 +62,29 @@ int whitespace(const char * str)
}
/**
+ * returns a string without its underscores
+ * \param replacespace true to insert a space where there was an underscore
+ */
+
+char *remove_underscores(const char *s, bool replacespace)
+{
+ size_t i, ii, len;
+ char *ret;
+ len = strlen(s);
+ ret = malloc(len + 1);
+ if (ret == NULL)
+ return NULL;
+ for (i = 0, ii = 0; i < len; i++) {
+ if (s[i] != '_')
+ ret[ii++] = s[i];
+ else if (replacespace)
+ ret[ii++] = ' ';
+ }
+ ret[ii] = '\0';
+ return ret;
+}
+
+/**
* Replace consecutive whitespace with a single space.
*
* \param s source string
diff --git a/utils/utils.h b/utils/utils.h
index 279bd73c8..74c01ec25 100644
--- a/utils/utils.h
+++ b/utils/utils.h
@@ -76,6 +76,7 @@ typedef struct
char * strip(char * const s);
int whitespace(const char * str);
char * squash_whitespace(const char * s);
+char *remove_underscores(const char *s, bool replacespace);
char *cnv_space2nbsp(const char *s);
bool is_dir(const char *path);
void regcomp_wrapper(regex_t *preg, const char *regex, int cflags);