diff options
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 Binary files differnew file mode 100644 index 000000000..1cb432828 --- /dev/null +++ b/!NetSurf/Resources/default.ico 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. @@ -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(¤t_time)->tm_yday; + int current_day = localtime(¤t_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 Binary files differnew file mode 100644 index 000000000..1cb432828 --- /dev/null +++ b/gtk/res/default.ico diff --git a/gtk/res/html.png b/gtk/res/html.png Binary files differnew file mode 100644 index 000000000..d44dcadce --- /dev/null +++ b/gtk/res/html.png 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"><b>Certificate chain</b></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> + |