├── debian ├── compat ├── docs ├── clean ├── watch ├── files ├── rules ├── control ├── changelog └── copyright ├── data ├── icons │ ├── 128x128 │ │ ├── yad.png │ │ └── Makefile.am │ ├── 16x16 │ │ ├── yad.png │ │ └── Makefile.am │ ├── 24x24 │ │ ├── yad.png │ │ └── Makefile.am │ ├── 32x32 │ │ ├── yad.png │ │ └── Makefile.am │ ├── 48x48 │ │ ├── yad.png │ │ └── Makefile.am │ ├── 96x96 │ │ ├── yad.png │ │ └── Makefile.am │ └── Makefile.am ├── misc │ ├── pfd │ ├── zenity.sh │ └── notify-send ├── yad-icon-browser.desktop.in ├── yad-settings.desktop.in ├── Makefile.am ├── yad.m4.in ├── yad.spec.in ├── yad-tools.1 └── yad.gschema.xml ├── AUTHORS ├── Makefile.am ├── po ├── LINGUAS ├── POTFILES.in └── Makevars ├── TODO ├── .gitignore ├── src ├── cpicker.h ├── Makefile.am ├── defaults.h ├── calendar.xpm ├── font.c ├── calendar.c ├── paned.c ├── app.c ├── dnd.c ├── file.c ├── about.c ├── notebook.c ├── scale.c ├── yad-settings.in ├── color.c ├── cpicker.c ├── entry.c ├── appindicator.c ├── browser.c ├── tools.c ├── notification.c ├── progress.c └── print.c ├── THANKS ├── README.md └── configure.ac /debian/compat: -------------------------------------------------------------------------------- 1 | 10 2 | -------------------------------------------------------------------------------- /debian/docs: -------------------------------------------------------------------------------- 1 | NEWS 2 | -------------------------------------------------------------------------------- /debian/clean: -------------------------------------------------------------------------------- 1 | data/yad-icon-browser.desktop 2 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=4 2 | https://github.com/v1cont/yad/archive/refs/tags/v\d+.\d+.tar.gz -------------------------------------------------------------------------------- /data/icons/128x128/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v1cont/yad/HEAD/data/icons/128x128/yad.png -------------------------------------------------------------------------------- /data/icons/16x16/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v1cont/yad/HEAD/data/icons/16x16/yad.png -------------------------------------------------------------------------------- /data/icons/24x24/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v1cont/yad/HEAD/data/icons/24x24/yad.png -------------------------------------------------------------------------------- /data/icons/32x32/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v1cont/yad/HEAD/data/icons/32x32/yad.png -------------------------------------------------------------------------------- /data/icons/48x48/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v1cont/yad/HEAD/data/icons/48x48/yad.png -------------------------------------------------------------------------------- /data/icons/96x96/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/v1cont/yad/HEAD/data/icons/96x96/yad.png -------------------------------------------------------------------------------- /data/icons/128x128/Makefile.am: -------------------------------------------------------------------------------- 1 | iconsdir = $(datadir)/icons/hicolor/128x128/apps 2 | dist_icons_DATA = yad.png 3 | -------------------------------------------------------------------------------- /data/icons/16x16/Makefile.am: -------------------------------------------------------------------------------- 1 | iconsdir = $(datadir)/icons/hicolor/16x16/apps 2 | dist_icons_DATA = yad.png 3 | -------------------------------------------------------------------------------- /data/icons/24x24/Makefile.am: -------------------------------------------------------------------------------- 1 | iconsdir = $(datadir)/icons/hicolor/24x24/apps 2 | dist_icons_DATA = yad.png 3 | -------------------------------------------------------------------------------- /data/icons/32x32/Makefile.am: -------------------------------------------------------------------------------- 1 | iconsdir = $(datadir)/icons/hicolor/32x32/apps 2 | dist_icons_DATA = yad.png 3 | -------------------------------------------------------------------------------- /data/icons/48x48/Makefile.am: -------------------------------------------------------------------------------- 1 | iconsdir = $(datadir)/icons/hicolor/48x48/apps 2 | dist_icons_DATA = yad.png 3 | -------------------------------------------------------------------------------- /data/icons/96x96/Makefile.am: -------------------------------------------------------------------------------- 1 | iconsdir = $(datadir)/icons/hicolor/96x96/apps 2 | dist_icons_DATA = yad.png 3 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Victor Ananjevsky 2 | 3 | Zenity Authors: 4 | Glynn Foster 5 | Mike Newman 6 | -------------------------------------------------------------------------------- /data/misc/pfd: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | echo "WARNING: pfd is deprecated. Please use yad-tools --pfd instead" > /dev/stderr 4 | exec yad-tools --pfd "$@" 5 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | ACLOCAL_AMFLAGS = -I m4 3 | 4 | SUBDIRS = src po data 5 | 6 | EXTRA_DIST = m4/ChangeLog COPYING ChangeLog.old NEWS README.md AUTHORS TODO THANKS 7 | -------------------------------------------------------------------------------- /debian/files: -------------------------------------------------------------------------------- 1 | yad-dbgsym_12.3.0-0.1_amd64.deb debug optional automatic=yes 2 | yad_12.3.0-0.1_amd64.buildinfo utils optional 3 | yad_12.3.0-0.1_amd64.deb utils optional 4 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | # yad translations 2 | # 3 | # please keep this list sorted alphabetically 4 | # 5 | de 6 | es 7 | fr 8 | it 9 | ka 10 | pt_BR 11 | sk 12 | uk 13 | zh_TW 14 | -------------------------------------------------------------------------------- /data/yad-icon-browser.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Name=Icon Browser 4 | Comment=Inspect GTK Icon Theme 5 | Categories=GTK;Development; 6 | Exec=yad-icon-browser 7 | Icon=yad 8 | Terminal=false 9 | Type=Application 10 | StartupNotify=true 11 | -------------------------------------------------------------------------------- /data/yad-settings.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Name=YAD settings 4 | Comment=Simple GUI for editing YAD settings 5 | Categories=GTK;Settings; 6 | Exec=yad-settings 7 | Icon=yad 8 | Terminal=false 9 | Type=Application 10 | StartupNotify=true 11 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | #DH_VERBOSE = 1 3 | 4 | export DEB_CFLAGS_MAINT_APPEND = -fgnu89-inline 5 | 6 | export DEB_BUILD_MAINT_OPTIONS = hardening=+all 7 | export V=1 8 | 9 | %: 10 | dh $@ --with autoreconf 11 | 12 | override_dh_auto_configure: 13 | dh_auto_configure -- --with-gtk=gtk3 --enable-html --enable-gio --enable-spell --enable-sourceview --enable-icon-browser 14 | -------------------------------------------------------------------------------- /data/misc/zenity.sh: -------------------------------------------------------------------------------- 1 | 2 | function zenity () 3 | { 4 | local ARGS 5 | ARGS= 6 | for a in "$@"; do 7 | case $a in 8 | --info) ARGS="$ARGS --image=gtk-dialog-info" ;; 9 | --question) ARGS="$ARGS --image=gtk-dialog-question" ;; 10 | --warning) ARGS="$ARGS --image=gtk-dialog-warning" ;; 11 | --error) ARGS="$ARGS --image=gtk-dialog-error" ;; 12 | *) ARGS="$ARGS $a" 13 | esac 14 | done 15 | eval set -- $ARGS 16 | yad $@ 17 | } 18 | export -f zenity 19 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - add actions to list, text-info and icons dialogs 2 | - use optional gtksourceview in text-info dialog (done) 3 | - add slideshow to picture dialog (reading uris from stdin) 4 | - add single model for completion and combo-boxes 5 | - add menu for select encodings in html dialog 6 | - add reverse check column for list dialog 7 | - add option for output format of boolean values (upper, lower, num) 8 | - add tooltips for labels 9 | - add custom handlers for edit and delete actions in editable lists 10 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | src/about.c 2 | src/app.c 3 | src/calendar.c 4 | src/entry.c 5 | src/file.c 6 | src/font.c 7 | src/form.c 8 | src/html.c 9 | src/icons.c 10 | src/main.c 11 | src/notification.c 12 | src/scale.c 13 | src/list.c 14 | src/option.c 15 | src/paned.c 16 | src/picture.c 17 | src/print.c 18 | src/progress.c 19 | src/color.c 20 | src/text.c 21 | src/notebook.c 22 | src/util.c 23 | src/browser.c 24 | src/tools.c 25 | src/yad-settings.sh 26 | data/yad-icon-browser.desktop.in 27 | data/yad-settings.desktop.in 28 | -------------------------------------------------------------------------------- /data/icons/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = 16x16 24x24 32x32 48x48 96x96 128x128 2 | 3 | gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor 4 | 5 | install-data-hook: 6 | @-if test -z "$(DESTDIR)"; then \ 7 | echo "Updating Gtk icon cache."; \ 8 | $(gtk_update_icon_cache); \ 9 | else \ 10 | echo "*** Icon cache not updated. Remember to run:"; \ 11 | echo "***"; \ 12 | echo "*** $(gtk_update_icon_cache)"; \ 13 | echo "***"; \ 14 | fi 15 | 16 | uninstall-local: 17 | rm -f $(DESTDIR)$(datadir)/icons/hicolor/icon-theme.cache; 18 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: yad 2 | Section: utils 3 | Priority: optional 4 | Maintainer: Gustavo Soares de Lima 5 | Build-Depends: debhelper (>=10), autotools-dev, libgtk-3-dev, pkg-config, intltool 6 | Standards-Version: 3.9.8 7 | Homepage: https://github.com/v1cont/yad/ 8 | 9 | Package: yad 10 | Architecture: any 11 | Depends: ${shlibs:Depends}, 12 | ${misc:Depends} 13 | Description: tool for creating graphical dialogs from shell scripts 14 | Yad allows you to display GTK+ dialog boxes from command line or shell 15 | scripts. It is similar to Zenity but with more dialog types and options. 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | configure 4 | build/ 5 | autom4te.cache/ 6 | intl/ 7 | m4/ 8 | .deps/ 9 | *.o 10 | *~ 11 | \#*\# 12 | aclocal.m4 13 | config.h 14 | config.h.in 15 | config.log 16 | config.status 17 | data/*.desktop 18 | data/yad.m4 19 | data/yad.spec 20 | po/Makefile.in.in 21 | po/Makevars.template 22 | po/POTFILES 23 | po/Rules-quot 24 | po/*.pot 25 | po/*.gmo 26 | po/*.sed 27 | po/*.header 28 | po/*.sin 29 | po/stamp-it 30 | po/stamp-po 31 | src/yad 32 | src/yad-icon-browser 33 | src/yad-tools 34 | src/yad-settings 35 | src/*.sh 36 | stamp-h1 37 | *.tar.xz 38 | build.log 39 | *.gschema.valid 40 | ABOUT-NLS 41 | ChangeLog -------------------------------------------------------------------------------- /data/misc/notify-send: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Defaults 4 | APP="notification" 5 | TIMEOUT=600 6 | ICON="dialog-information" 7 | TITLE= 8 | BODY= 9 | 10 | # Parse command line 11 | OPTIND=1 12 | while getopts a:i:t: opt ; do 13 | case "$opt" in 14 | a) APP=$OPTARG ;; 15 | i) ICON=$OPTARG ;; 16 | t) TIMEOUT=$OPTARG ;; 17 | esac 18 | done 19 | shift $(($OPTIND - 1)) 20 | [[ "$1" == '--' ]] && shift 21 | 22 | TITLE="$1" 23 | shift 24 | BODY="$@" 25 | 26 | gdbus call --session --dest org.freedesktop.Notifications \ 27 | --object-path /org/freedesktop/Notifications \ 28 | --method org.freedesktop.Notifications.Notify \ 29 | "$APP" 0 "$ICON" "$TITLE" "$BODY" "[]" "{}" $TIMEOUT &> /dev/null 30 | -------------------------------------------------------------------------------- /data/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = icons 2 | 3 | desktop_in_files = 4 | if BUILD_IB 5 | desktop_in_files += yad-icon-browser.desktop.in 6 | endif 7 | if !STANDALONE 8 | desktop_in_files += yad-settings.desktop.in 9 | endif 10 | 11 | desktopdir = $(datadir)/applications 12 | desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) 13 | 14 | %.desktop: %.desktop.in 15 | $(AM_V_GEN)$(MSGFMT) --desktop --template $< -d $(top_srcdir)/po -o $@ 16 | 17 | gsettings_SCHEMAS = yad.gschema.xml 18 | @GSETTINGS_RULES@ 19 | 20 | dist_man_MANS = yad.1 21 | if BUILD_TOOLS 22 | dist_man_MANS += yad-tools.1 23 | endif 24 | 25 | m4dir = $(datadir)/aclocal 26 | m4_DATA = yad.m4 27 | 28 | EXTRA_DIST = $(desktop_in_files) $(gsettings_SCHEMAS) misc 29 | 30 | DISTCLEANFILES = $(desktop_DATA) $(m4_DATA) yad.spec 31 | -------------------------------------------------------------------------------- /src/cpicker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2020-2025, Victor Ananjevsky 18 | */ 19 | 20 | #ifndef __CPICKER_H__ 21 | #define __CPICKER_H__ 22 | 23 | #include 24 | 25 | void yad_get_screen_color (GtkWidget *widget); 26 | 27 | #endif /* __CPICKER_H__ */ 28 | -------------------------------------------------------------------------------- /data/yad.m4.in: -------------------------------------------------------------------------------- 1 | ## -*- Autoconf -*- 2 | # 3 | # Copyright (c) 2008-2011, Vitor Ananjevsky 4 | # 5 | # This file is free software; the Free Software Foundation 6 | # gives unlimited permission to copy and/or distribute it, 7 | # with or without modifications, as long as this notice is preserved. 8 | 9 | # AM_PATH_YAD([MINIMUM-VERSION],[ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) 10 | # --------------------------------------------------------------------------- 11 | AC_DEFUN([AM_PATH_YAD],[ 12 | m4_if([$1],[],[ 13 | dnl No version check is needed. 14 | if test -z "$YAD"; then 15 | AC_PATH_PROG([YAD], yad, :) 16 | fi 17 | ], [ 18 | dnl A version check is needed. 19 | if test -z "$YAD"; then 20 | AC_PATH_PROG([YAD], yad, :) 21 | fi 22 | AC_MSG_CHECKING([whether yad version >= $1]) 23 | m4_define([yad_version],[@VERSION@]) 24 | m4_if(m4_version_compare(yad_version,[$1]),[-1], 25 | [AC_MSG_ERROR([too old (]yad_version[)])], 26 | [AC_MSG_RESULT(yad_version)]) 27 | ]) 28 | 29 | if test "$YAD" = :; then 30 | dnl Run any user-specified action, or abort. 31 | m4_default([$3], [AC_MSG_ERROR([Yad not found])]) 32 | else 33 | dnl Run any user-specified action. 34 | m4_if([$2],[],[true],[$2]) 35 | AC_SUBST([YAD]) 36 | fi 37 | ]) 38 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CPPFLAGS = -DLOCALEDIR=\""$(datadir)/locale"\" 2 | 3 | bin_PROGRAMS = yad 4 | 5 | if !STANDALONE 6 | bin_SCRIPTS = yad-settings 7 | endif 8 | 9 | CPICKER_SOURCES = cpicker.c cpicker.h 10 | 11 | yad_SOURCES = \ 12 | about.c \ 13 | app.c \ 14 | calendar.c \ 15 | color.c \ 16 | dnd.c \ 17 | entry.c \ 18 | file.c \ 19 | font.c \ 20 | form.c \ 21 | icons.c \ 22 | list.c \ 23 | notebook.c \ 24 | option.c \ 25 | paned.c \ 26 | picture.c \ 27 | print.c \ 28 | progress.c \ 29 | scale.c \ 30 | text.c \ 31 | util.c \ 32 | main.c \ 33 | yad.h \ 34 | calendar.xpm \ 35 | $(CPICKER_SOURCES) 36 | 37 | if TRAY 38 | yad_SOURCES += notification.c 39 | endif 40 | 41 | if HTML 42 | yad_SOURCES += html.c 43 | endif 44 | 45 | if APPINDICATOR 46 | yad_SOURCES += appindicator.c 47 | endif 48 | 49 | if STANDALONE 50 | yad_SOURCES += defaults.h 51 | endif 52 | 53 | yad_CFLAGS = $(GTK_CFLAGS) $(HTML_CFLAGS) $(SPELL_CFLAGS) $(SOURCEVIEW_CFLAGS) $(APPINDICATOR_CFLAGS) 54 | yad_LDADD = $(GTK_LIBS) $(HTML_LIBS) $(SPELL_LIBS) $(SOURCEVIEW_LIBS) $(APPINDICATOR_LIBS) 55 | 56 | if BUILD_TOOLS 57 | bin_PROGRAMS += yad-tools 58 | 59 | yad_tools_SOURCES = tools.c $(CPICKER_SOURCES) 60 | yad_tools_CFLAGS = $(GTK_CFLAGS) $(SPELL_CFLAGS) $(SOURCEVIEW_CFLAGS) 61 | yad_tools_LDADD = $(GTK_LIBS) $(SPELL_LIBS) $(SOURCEVIEW_LIBS) 62 | endif 63 | 64 | if BUILD_IB 65 | bin_PROGRAMS += yad-icon-browser 66 | 67 | yad_icon_browser_SOURCES = browser.c 68 | yad_icon_browser_CFLAGS = $(GTK_CFLAGS) 69 | yad_icon_browser_LDADD = $(GTK_LIBS) 70 | endif 71 | -------------------------------------------------------------------------------- /data/yad.spec.in: -------------------------------------------------------------------------------- 1 | # norootforbuild 2 | 3 | Name: yad 4 | Version: @VERSION@ 5 | Release: 1 6 | 7 | Summary: A fork of Zenity with many improvements 8 | License: GPLv3 9 | Group: Development/Tools/GUI Builders 10 | URL: http://code.google.com/p/yad/ 11 | 12 | Source0: %{name}-%{version}.tar.bz2 13 | 14 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot 15 | 16 | BuildRequires: gtk2-devel intltool pkgconfig 17 | 18 | 19 | %description 20 | Yad (yet another dialog) is a fork of Zenity with many improvements, such as 21 | custom buttons, additional dialogs, pop-up menu in notification icon and more. 22 | 23 | There were two main reasons to make this fork. The first one is to remove 24 | dependencies on deprecated libraries, such as libglade and gnome-canvas. 25 | And the second one - as for me, Zenity looks like an abandoned project. 26 | Its ChangeLog consists of just "bump version to..." and "translation updated" 27 | for the long time, but many interesting ideas which are ignored by 28 | developers/maintainers were in GNOME Bugzilla. 29 | 30 | 31 | %debug_package 32 | 33 | 34 | %prep 35 | %setup -q -n %{name}-%{version} 36 | 37 | 38 | %build 39 | %configure 40 | %__make %{?jobs:-j%{jobs}} 41 | 42 | 43 | %install 44 | %makeinstall 45 | %find_lang %{name} 46 | 47 | 48 | %clean 49 | rm -rf "%{buildroot}" 50 | 51 | 52 | %files -f %{name}.lang 53 | %defattr(-,root,root,-) 54 | %doc AUTHORS ChangeLog COPYING README THANKS TODO 55 | %{_bindir}/%{name} 56 | %{_datadir}/pixmaps/%{name}.png 57 | %{_mandir}/man1/%{name}.1.gz 58 | 59 | 60 | %changelog 61 | * Tue Jan 05 2010 - Detlef Reichelt - 0.0.8 62 | - initial build for PackMan <0.0.8> 63 | -------------------------------------------------------------------------------- /src/defaults.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2020-2025, Victor Ananjevsky 18 | */ 19 | 20 | #ifndef __YAD_DEFS_H__ 21 | #define __YAD_DEFS_H__ 22 | 23 | #ifndef BORDERS 24 | #define BORDERS 5 25 | #endif 26 | 27 | #ifndef REMAIN 28 | #define SHOW_REMAIN FALSE 29 | #else 30 | #define SHOW_REMAIN TRUE 31 | #endif 32 | 33 | #ifndef COMBO_EDIT 34 | #define COMBO_ALWAYS_EDIT FALSE 35 | #else 36 | #define COMBO_ALWAYS_EDIT TRUE 37 | #endif 38 | 39 | #ifndef TERM_CMD 40 | #define TERM_CMD "xterm -e '%s'" 41 | #endif 42 | 43 | #ifndef OPEN_CMD 44 | #define OPEN_CMD "xdg-open '%s'" 45 | #endif 46 | 47 | #ifndef DATE_FMT 48 | #define DATE_FMT "%x" 49 | #endif 50 | 51 | #ifndef URI_COLOR 52 | #define URI_COLOR "blue" 53 | #endif 54 | 55 | #ifndef MAX_TABS 56 | #define MAX_TABS 100 57 | #endif 58 | 59 | #ifndef MARK1_COLOR 60 | #define MARK1_COLOR "lightgreen" 61 | #endif 62 | 63 | #ifndef MARK2_COLOR 64 | #define MARK2_COLOR "pink" 65 | #endif 66 | 67 | #endif /* __YAD_DEFS_H__ */ 68 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | yad (12.3.0-0.1) unstable; urgency=medium 2 | 3 | * Non-maintainer upload. 4 | * New version. 5 | 6 | -- Peter Gervai Mon, 17 Apr 2023 13:52:02 +0200 7 | 8 | yad (0.40.0-1) unstable; urgency=medium 9 | 10 | * New upstream release (Closes: #876226). 11 | 12 | -- Gustavo Soares de Lima Sun, 09 Sep 2018 11:49:15 -0300 13 | 14 | yad (0.38.2-1) unstable; urgency=medium 15 | 16 | * New upstream release. 17 | * debian/clean: 18 | - Added to remove an extra file created by build process. 19 | * debian/control: 20 | - Bump to DH 10. 21 | * debian/copyright: 22 | - Changed license to BSD-3-Clause (Closes: #836877). 23 | - Updated with po/* authors. 24 | * debian/rules: 25 | - Build with enable-gio. 26 | - Build with enable-html. 27 | - Build with icon-browser (Closes: #849814). 28 | - Build with enable-sourceview. 29 | - Build with enable-spell. 30 | - Removed unnecessary lines. 31 | * debian/watch: 32 | - Updated to version 4. 33 | 34 | -- Gustavo Soares de Lima Tue, 24 Jan 2017 23:23:49 -0200 35 | 36 | yad (0.37.0-1) unstable; urgency=medium 37 | 38 | * New upstream release 39 | 40 | -- Gustavo Soares de Lima Tue, 16 Aug 2016 18:49:00 +0000 41 | 42 | yad (0.27.0-1.1) unstable; urgency=medium 43 | 44 | * Non-maintainer upload. 45 | * Build with -fgnu89-inline. Closes: #790779. 46 | 47 | -- Matthias Klose Sat, 25 Jul 2015 13:31:28 +0200 48 | 49 | yad (0.27.0-1) unstable; urgency=low 50 | 51 | * Initial release (Closes: #737599) 52 | 53 | -- Gustavo Soares de Lima Thu, 19 Feb 2015 19:37:03 -0200 54 | -------------------------------------------------------------------------------- /data/yad-tools.1: -------------------------------------------------------------------------------- 1 | .TH YAD-TOOLS "1" "April 2021" "yad-tools" "User Commands" 2 | 3 | .SH NAME 4 | yad-tools \- show some miscellaneous stuff. 5 | 6 | .SH SYNOPSIS 7 | .B yad-tools 8 | .RI [OPTIONS] 9 | .RI STRING 10 | 11 | .SH DESCRIPTION 12 | \fByad-tools\fR is a small command-line utility for getting information that may be usefull in scripts. 13 | 14 | .SH OPTIONS 15 | 16 | .SS General options 17 | .TP 18 | \fB\-f\fR, \fB\-\-pfd\fR 19 | This mode is intended to transform font names from pango to xft specification and vice versa. 20 | Additional argument is font name. 21 | .TP 22 | \fB\-i\fR, \fB\-\-icon\fR 23 | This mode is intended to get full path to icon file from icon name. 24 | Additional argument is icon name. 25 | .TP 26 | \fB\-c\fR, \fB\-\-color\fR 27 | This mode is intended for works with colors. 28 | .TP 29 | .B \-\-show-langs 30 | Show list of available languages for spell checking. Works only if yad built with \fIGSpell\fP support. 31 | .TP 32 | .B \-\-show-themes 33 | Show list of available GtkSourceView themes. Works only if yad built with \fIGtkSourceView\fP support. 34 | 35 | .SS PFD mode options 36 | .TP 37 | \fB\-x\fR, \fB\-\-xft\fR 38 | Print font name in xft format. This is default. 39 | .TP 40 | \fB\-p\fR, \fB\-\-pango\fR 41 | Print font name in pango format. 42 | 43 | .SS Icon mode options 44 | .TP 45 | \fB\-s\fR, \fB\-\-size\fR=\fISIZE\fP 46 | Use specified icon size. Default is 24. 47 | .TP 48 | \fB\-t\fR, \fB\-\-type\fR=\fITYPE\fP 49 | Obtain icon size from one of predefined GTK+ types. \fITYPE\fP is one of the following \fImenu\fP, \fIbutton\fP, \fIsmall_toolbar\fP, \fIlarge_toolbar\fP, \fIdnd\fP or \fIdialog\fP, 50 | .TP 51 | \fB\-m\fR, \fB\-\-mime\fP 52 | Get generic icon name for specified mime type. 53 | .TP 54 | \fB\-\-theme\fR=\fITHEME\fP 55 | Use specified icon theme instead of default. 56 | 57 | .SS Color mode options 58 | .TP 59 | \fB\-\-pick\fP 60 | Pick up screen color. 61 | -------------------------------------------------------------------------------- /src/calendar.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static const char * calendar_xpm[] = { 3 | "16 16 79 1", 4 | " c None", 5 | ". c #898D88", 6 | "+ c #898B86", 7 | "@ c #8B8D89", 8 | "# c #945D04", 9 | "$ c #8F5A02", 10 | "% c #8E5902", 11 | "& c #878984", 12 | "* c #BFC0BB", 13 | "= c #D8D9D7", 14 | "- c #945D05", 15 | "; c #D9AC65", 16 | "> c #DEB36F", 17 | ", c #A5A7A3", 18 | "' c #E6E8E5", 19 | ") c #A9AAA7", 20 | "! c #DFB370", 21 | "~ c #DFB470", 22 | "{ c #F8F8F8", 23 | "] c #E0B571", 24 | "^ c #DCB069", 25 | "/ c #555753", 26 | "( c #D3D5D2", 27 | "_ c #989A95", 28 | ": c #D4D6D3", 29 | "< c #E0B671", 30 | "[ c #DEB26E", 31 | "} c #FFFFFF", 32 | "| c #C1C2BF", 33 | "1 c #91938F", 34 | "2 c #C2C3C0", 35 | "3 c #E1B671", 36 | "4 c #F5F5F5", 37 | "5 c #FDFDFD", 38 | "6 c #E6E6E6", 39 | "7 c #DEB26D", 40 | "8 c #808080", 41 | "9 c #686868", 42 | "0 c #5C5C5C", 43 | "a c #989898", 44 | "b c #DEB26C", 45 | "c c #CFCFCF", 46 | "d c #3F3F3F", 47 | "e c #E2B671", 48 | "f c #DFB36C", 49 | "g c #6A6A6A", 50 | "h c #282828", 51 | "i c #A1A1A1", 52 | "j c #E2B570", 53 | "k c #E0E0E0", 54 | "l c #2B2B2B", 55 | "m c #959691", 56 | "n c #888A85", 57 | "o c #646661", 58 | "p c #E2B670", 59 | "q c #616161", 60 | "r c #656565", 61 | "s c #636363", 62 | "t c #8F8F8F", 63 | "u c #EEEEED", 64 | "v c #979893", 65 | "w c #646662", 66 | "x c #E3B670", 67 | "y c #D3D7CF", 68 | "z c #DFB26B", 69 | "A c #E4B76F", 70 | "B c #DBAD64", 71 | "C c #E0B36B", 72 | "D c #E1B46C", 73 | "E c #E1B36C", 74 | "F c #E1B46D", 75 | "G c #E2B56D", 76 | "H c #E2B46D", 77 | "I c #E2B66E", 78 | "J c #E3B56F", 79 | "K c #E3B66F", 80 | "L c #E4B66F", 81 | "M c #DFB169", 82 | "N c #945F05", 83 | " .+@ .+@ ", 84 | "#$%%&*&%%&=&%%$-", 85 | "$;>>,')!~,{)]]^$", 86 | "%>//&(_//&:_//<%", 87 | "%[/}|12}}|1|}/3%", 88 | "%[/}45466454}/3%", 89 | "%7/}66890a66}/3%", 90 | "%b/}6666cd66}/e%", 91 | "%f/}666ghi66}/j%", 92 | "%f/}6666kl6mnop%", 93 | "%f/}66qrst6&u/p%", 94 | "%f/}}}}}}}}vnwx%", 95 | "%f/yyyyyyyyyy/x%", 96 | "%z////////////A%", 97 | "$BCDEFFGHGIJKLM$", 98 | "-$%%%%%%%%%%%%$N"}; 99 | -------------------------------------------------------------------------------- /THANKS: -------------------------------------------------------------------------------- 1 | "Zenity Authors", 2 | "=======", 3 | "Glynn Foster ", 4 | "Mike Newman ", 5 | "", 6 | "Patches from the following people", 7 | "=================================", 8 | "Darren Adams " 9 | "Timo Aaltonen ", 10 | "Peter Astrand ", 11 | "Jonathan Blandford ", 12 | "Paul Bolle ", 13 | "Paolo Borelli ", 14 | "Leonardo Boshell

", 15 | "Ross Burton ", 16 | "Damien Carbery ", 17 | "Anders Carlsson ", 18 | "Ed Catmur ", 19 | "Nicholas Curran ", 20 | "John Fleck ", 21 | "Sebastian Heinlein ", 22 | "James Henstridge ", 23 | "Chris Lahey ", 24 | "Mihai T Lazarescu ", 25 | "Sebastian Kapfer ", 26 | "Tomasz Koczko ", 27 | "Jordi Mallach ", 28 | "Kjartan Maraas ", 29 | "Breda McColgan ", 30 | "Baptiste Mille-Mathias ", 31 | "Buhan Milne ", 32 | "Christian Monneckes ", 33 | "Ivan Noris ", 34 | "Carlos Parra ", 35 | "Havoc Pennington ", 36 | "Jan Arne Petersen ", 37 | "Kevin C Krinke ", 38 | "Sriram Ramkrishna ", 39 | "Kristian Rietveld ", 40 | "Lucas Rocha ", 41 | "Christian Rose ", 42 | "Jakub Steiner ", 43 | "Luke Suchocki ", 44 | "Daniel d'Surreal ", 45 | "Hidetoshi Tajima ", 46 | "Tom Tromey ", 47 | "Yann ", 48 | "Norman Rasmussen ", 49 | "Benoît Dejean ", 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yet Another Dialog 2 | ==================== 3 | 4 | NB: 5 | 6 | Well, sorry for silence but i'm too busy right now (fucking war, 7 | fucking russians). After all i'm still alive 8 | 9 | Just want to say - YAD is not an abandoned project. Because of 10 | external circumstances i cannot maintain it very actively, but i lurk 11 | for all of yours reports and proposals and keeps it in my mind 12 | 13 | Thanks for understanding and patience 14 | 15 | ========= 16 | 17 | Program allows you to display GTK+ dialog boxes from command line or 18 | shell scripts. YAD depends on GTK+ only. Minimal GTK+ version is 3.22.0 19 | 20 | This software is licensed under the GPL v.3 21 | 22 | Project homepage: https://github.com/v1cont/yad 23 | Complex examples: https://github.com/v1cont/yad/wiki/YAD-Examples 24 | Mailing list: http://groups.google.com/group/yad-common 25 | 26 | Some miscellaneous stuff can be found in data/misc directory including notify-send script 27 | and simple zenity-compatible wrapper 28 | 29 | A fresh gtk2 branch of YAD can be obtained from this repository - https://github.com/step-/yad 30 | 31 | Building git version 32 | ---------------------- 33 | 34 | Get git version with command 35 | 36 | git clone https://github.com/v1cont/yad.git yad-dialog-code 37 | 38 | Before run the standard ./configure && make && make install procedure 39 | you need to generate build scripts. This can be done by running command 40 | 41 | autoreconf -ivf 42 | 43 | You must manually run gtk-update-icon-cache after installation. 44 | 45 | For successfully build you may need to install the following packages: 46 | * GNU Autotools (https://www.gnu.org/software/autoconf/ http://www.gnu.org/software/automake/) 47 | * gettext >= 0.19.7 (https://www.gnu.org/software/gettext/) 48 | * GTK+ >= 3.22.0 (http://www.gtk.org) 49 | with appropriate *-dev* packages depending on your distro 50 | 51 | Additionally, you can build yad with the following libraries: 52 | * Webkit - for supporting HTML dialog (http://webkitgtk.org) 53 | * GtkSourceView - for enabling syntax highlighting in text-info dialog (https://wiki.gnome.org/Projects/GtkSourceView) 54 | * GSpell - for support spell checking in text fields (https://wiki.gnome.org/Projects/gspell) 55 | * Libappindicator - for support appindicator extension (https://ayatana-indicators.org/) 56 | 57 | In standalone build (configure option --enable-standalone) some defaults can be redefined with the following defines 58 | 59 | BORDERS - set the default border width around dialog. Default is 5 60 | REMAIN - if defined, timeout indicator will show the remaining time 61 | COMBO_EDIT - if defined, combo-box in entry dialog will be always editable 62 | TERM_CMD - string with terminal command. Default is "xterm -e '%s'" 63 | OPEN_CMD - string with open command. Default is "xdg-open '%s'" 64 | DATE_FMT - string with date output format. Default is "%x". See strftime(3) for details 65 | URI_COLOR - color for URIs in text-info dialog. Default is blue 66 | MARK1_COLOR - color for first type of text marks in text-info dialog. Default is lightgreen 67 | MARK2_COLOR - color for second type of text marks in text-info dialog. Default is pink 68 | MAX_TABS - set the number of tabs for tabbed dialog. Default is 100 69 | 70 | Defines can be added througs CFLAGS environment variable 71 | -------------------------------------------------------------------------------- /src/font.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include "yad.h" 21 | 22 | static GtkWidget *font; 23 | 24 | static void 25 | font_activated_cb (GtkFontChooser *w, gchar *fn, gpointer d) 26 | { 27 | if (options.plug == -1) 28 | yad_exit (options.data.def_resp); 29 | } 30 | 31 | static void 32 | realize_cb (GtkWidget * w, gpointer d) 33 | { 34 | gtk_font_chooser_set_font (GTK_FONT_CHOOSER (w), options.common_data.font); 35 | } 36 | 37 | GtkWidget * 38 | font_create_widget (GtkWidget * dlg) 39 | { 40 | GtkWidget *w; 41 | 42 | w = font = gtk_font_chooser_widget_new (); 43 | gtk_widget_set_name (w, "yad-font-widget"); 44 | 45 | if (options.font_data.preview) 46 | gtk_font_chooser_set_preview_text (GTK_FONT_CHOOSER (w), options.font_data.preview); 47 | 48 | g_signal_connect (G_OBJECT (w), "font-activated", G_CALLBACK (font_activated_cb), NULL); 49 | 50 | /* font must be set after widget inserted in toplevel */ 51 | if (options.common_data.font) 52 | g_signal_connect_after (G_OBJECT (w), "realize", G_CALLBACK (realize_cb), NULL); 53 | 54 | return w; 55 | } 56 | 57 | void 58 | font_print_result (void) 59 | { 60 | if (options.font_data.separate_output) 61 | { 62 | PangoFontFace *face; 63 | PangoFontFamily *family; 64 | gint size; 65 | 66 | face = gtk_font_chooser_get_font_face (GTK_FONT_CHOOSER (font)); 67 | family = gtk_font_chooser_get_font_family (GTK_FONT_CHOOSER (font)); 68 | size = gtk_font_chooser_get_font_size (GTK_FONT_CHOOSER (font)); 69 | 70 | if (options.common_data.quoted_output) 71 | { 72 | gchar *q1 = g_shell_quote (pango_font_family_get_name (family)); 73 | gchar *q2 = g_shell_quote (pango_font_face_get_face_name (face)); 74 | 75 | g_printf ("%s%s%s%s%d\n", q1, options.common_data.separator, q2, 76 | options.common_data.separator, size / PANGO_SCALE); 77 | 78 | g_free (q1); 79 | g_free (q2); 80 | } 81 | else 82 | { 83 | g_printf ("%s%s%s%s%d\n", pango_font_family_get_name (family), options.common_data.separator, 84 | pango_font_face_get_face_name (face), options.common_data.separator, size / PANGO_SCALE); 85 | } 86 | } 87 | else 88 | { 89 | gchar *fn = gtk_font_chooser_get_font (GTK_FONT_CHOOSER (font)); 90 | 91 | if (options.common_data.quoted_output) 92 | { 93 | gchar *buf = g_shell_quote (fn); 94 | g_printf ("%s\n", buf); 95 | g_free (buf); 96 | } 97 | else 98 | g_printf ("%s\n", fn); 99 | 100 | g_free (fn); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: yad 3 | Source: https://github.com/v1cont/yad 4 | 5 | Files: * 6 | Copyright: 2009-2017 Victor Ananjevsky 7 | Glynn Foster 8 | Mike Newman 9 | License: GPL-3 10 | 11 | Files: po/* 12 | Copyright: 1995-1997 Ulrich Drepper 13 | 2003 Stephen Kennedy 14 | 2004-2008 Rodney Dawes 15 | 2006-2010 Claude Paroz 16 | 2006 Jonathan Ernst 17 | 2007 Robert-Andreas Mauchin 18 | 2009-2010 Bruno Brouard 19 | 2009 Manfred Mueller aka Quax 20 | 2009-2016 Victor Ananjevsky 21 | 2011 Yannou90 22 | 2012 Wei-Lun Chao 23 | 2013-2017 Gustavo Soares de Lima 24 | 2013 Slavko 25 | 2017 Angela Fernanda Ferreira 26 | License: GPL-3 27 | 28 | Files: debian/* 29 | Copyright: 2015-2017 Gustavo Soares de Lima 30 | License: BSD-3-Clause 31 | 32 | License: GPL-3 33 | This package is free software; you can redistribute it and/or modify 34 | it under the terms of the GNU General Public License as published by 35 | the Free Software Foundation; either version 3 of the License, or 36 | (at your option) any later version. 37 | . 38 | This package is distributed in the hope that it will be useful, 39 | but WITHOUT ANY WARRANTY; without even the implied warranty of 40 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 41 | GNU General Public License for more details. 42 | . 43 | You should have received a copy of the GNU General Public License 44 | along with this program. If not, see 45 | . 46 | On Debian systems, the complete text of the GNU General 47 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 48 | 49 | License: BSD-3-Clause 50 | Redistribution and use in source and binary forms, with or without 51 | modification, are permitted provided that the following conditions 52 | are met: 53 | 1. Redistributions of source code must retain the above copyright 54 | notice, this list of conditions and the following disclaimer. 55 | 2. Redistributions in binary form must reproduce the above copyright 56 | notice, this list of conditions and the following disclaimer in the 57 | documentation and/or other materials provided with the distribution. 58 | 3. Neither the name of the MIPS Technologies, Inc., nor the names of its 59 | contributors may be used to endorse or promote products derived from 60 | this software without specific prior written permission. 61 | . 62 | THIS SOFTWARE IS PROVIDED BY THE MIPS TECHNOLOGIES, INC. ``AS IS'' AND 63 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 | ARE DISCLAIMED. IN NO EVENT SHALL THE MIPS TECHNOLOGIES, INC. BE LIABLE 66 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 | SUCH DAMAGE. 73 | -------------------------------------------------------------------------------- /po/Makevars: -------------------------------------------------------------------------------- 1 | # Makefile variables for PO directory in any package using GNU gettext. 2 | # 3 | # Copyright (C) 2003-2025 Free Software Foundation, Inc. 4 | # This file is free software; the Free Software Foundation gives 5 | # unlimited permission to use, copy, distribute, and modify it. 6 | 7 | # Usually the message domain is the same as the package name. 8 | DOMAIN = yad 9 | 10 | # These two variables depend on the location of this directory. 11 | subdir = po 12 | top_builddir = .. 13 | 14 | # These options get passed to xgettext. 15 | XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ 16 | 17 | # This is the copyright holder that gets inserted into the header of the 18 | # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding 19 | # package. (Note that the msgid strings, extracted from the package's 20 | # sources, belong to the copyright holder of the package.) Translators are 21 | # expected to transfer the copyright for their translations to this person 22 | # or entity, or to disclaim their copyright. The empty string stands for 23 | # the public domain; in this case the translators are expected to disclaim 24 | # their copyright. 25 | COPYRIGHT_HOLDER = Victor Ananjevsky 26 | 27 | # This tells whether or not to prepend "GNU " prefix to the package 28 | # name that gets inserted into the header of the $(DOMAIN).pot file. 29 | # Possible values are "yes", "no", or empty. If it is empty, try to 30 | # detect it automatically by scanning the files in $(top_srcdir) for 31 | # "GNU packagename" string. 32 | PACKAGE_GNU = 33 | 34 | # This is the email address or URL to which the translators shall report 35 | # bugs in the untranslated strings: 36 | # - Strings which are not entire sentences, see the maintainer guidelines 37 | # in the GNU gettext documentation, section 'Preparing Strings'. 38 | # - Strings which use unclear terms or require additional context to be 39 | # understood. 40 | # - Strings which make invalid assumptions about notation of date, time or 41 | # money. 42 | # - Pluralisation problems. 43 | # - Incorrect English spelling. 44 | # - Incorrect formatting. 45 | # It can be your email address, or a mailing list address where translators 46 | # can write to without being subscribed, or the URL of a web page through 47 | # which the translators can contact you. 48 | MSGID_BUGS_ADDRESS = victor@sanana.kiev.ua 49 | 50 | # This is the list of locale categories, beyond LC_MESSAGES, for which the 51 | # message catalogs shall be used. It is usually empty. 52 | EXTRA_LOCALE_CATEGORIES = 53 | 54 | # This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt' 55 | # context. Possible values are "yes" and "no". Set this to yes if the 56 | # package uses functions taking also a message context, like pgettext(), or 57 | # if in $(XGETTEXT_OPTIONS) you define keywords with a context argument. 58 | USE_MSGCTXT = no 59 | 60 | # These options get passed to msgmerge. 61 | # Useful options are in particular: 62 | # --previous to keep previous msgids of translated messages, 63 | # --quiet to reduce the verbosity. 64 | MSGMERGE_OPTIONS = 65 | 66 | # These options get passed to msginit. 67 | # If you want to disable line wrapping when writing PO files, add 68 | # --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and 69 | # MSGINIT_OPTIONS. 70 | MSGINIT_OPTIONS = 71 | 72 | # This tells whether or not to regenerate a PO file when $(DOMAIN).pot 73 | # has changed. Possible values are "yes" and "no". Set this to no if 74 | # the POT file is checked in the repository and the version control 75 | # program ignores timestamps. 76 | PO_DEPENDS_ON_POT = yes 77 | 78 | # This tells whether or not to forcibly update $(DOMAIN).pot and 79 | # regenerate PO files on "make dist". Possible values are "yes" and 80 | # "no". Set this to no if the POT file and PO files are maintained 81 | # externally. 82 | DIST_DEPENDS_ON_UPDATE_PO = yes 83 | -------------------------------------------------------------------------------- /src/calendar.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | 22 | #include "yad.h" 23 | 24 | static GtkWidget *calendar; 25 | 26 | static GHashTable *details; 27 | 28 | static void 29 | parse_details () 30 | { 31 | FILE *f; 32 | 33 | details = g_hash_table_new (g_str_hash, g_str_equal); 34 | 35 | /* open details file */ 36 | f = fopen (options.calendar_data.details, "r"); 37 | if (f == NULL) 38 | { 39 | g_printerr (_("Cannot open file '%s': %s\n"), options.common_data.uri, g_strerror (errno)); 40 | return; 41 | } 42 | 43 | /* read details file */ 44 | while (!feof (f)) 45 | { 46 | gchar buf[4096]; 47 | 48 | /* read string */ 49 | memset (buf, 0, 4096); 50 | if (fgets (buf, 4096, f) == NULL) 51 | break; 52 | if (strlen (buf) > 0) 53 | { 54 | gchar **dtl = g_strsplit (buf, " ", 2); 55 | g_hash_table_insert (details, dtl[0], dtl[1]); 56 | } 57 | } 58 | 59 | fclose (f); 60 | } 61 | 62 | static gchar * 63 | get_details (GtkCalendar * cal, guint year, guint month, guint day, gpointer data) 64 | { 65 | GDate *d; 66 | gchar time_string[128]; 67 | gchar *str = NULL; 68 | 69 | d = g_date_new_dmy (day, month + 1, year); 70 | if (g_date_valid (d)) 71 | { 72 | g_date_strftime (time_string, 127, options.common_data.date_format, d); 73 | str = (gchar *) g_hash_table_lookup (details, time_string); 74 | } 75 | g_date_free (d); 76 | 77 | if (str) 78 | return g_strdup (str); 79 | 80 | return NULL; 81 | } 82 | 83 | static void 84 | double_click_cb (GtkWidget * w, gpointer data) 85 | { 86 | if (options.plug == -1) 87 | yad_exit (options.data.def_resp); 88 | } 89 | 90 | GtkWidget * 91 | calendar_create_widget (GtkWidget * dlg) 92 | { 93 | GtkWidget *w; 94 | gint cal_opts; 95 | 96 | w = calendar = gtk_calendar_new (); 97 | gtk_widget_set_name (w, "yad-calendar-widget"); 98 | 99 | if (options.calendar_data.month > 0 || options.calendar_data.year > 0) 100 | gtk_calendar_select_month (GTK_CALENDAR (w), options.calendar_data.month - 1, options.calendar_data.year); 101 | if (options.calendar_data.day > 0) 102 | gtk_calendar_select_day (GTK_CALENDAR (w), options.calendar_data.day); 103 | 104 | if (options.calendar_data.details) 105 | { 106 | parse_details (); 107 | gtk_calendar_set_detail_func (GTK_CALENDAR (w), get_details, NULL, NULL); 108 | } 109 | 110 | cal_opts = GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES; 111 | if (options.calendar_data.weeks) 112 | cal_opts |= GTK_CALENDAR_SHOW_WEEK_NUMBERS; 113 | gtk_calendar_set_display_options (GTK_CALENDAR (w), cal_opts); 114 | 115 | g_signal_connect (w, "day-selected-double-click", G_CALLBACK (double_click_cb), dlg); 116 | 117 | return w; 118 | } 119 | 120 | void 121 | calendar_print_result (void) 122 | { 123 | guint day, month, year; 124 | gchar time_string[128]; 125 | GDate *date = NULL; 126 | 127 | gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day); 128 | date = g_date_new_dmy (day, month + 1, year); 129 | g_date_strftime (time_string, 127, options.common_data.date_format, date); 130 | g_print ("%s\n", time_string); 131 | } 132 | -------------------------------------------------------------------------------- /src/paned.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "yad.h" 35 | 36 | static GtkWidget *paned; 37 | 38 | GtkWidget * 39 | paned_create_widget (GtkWidget * dlg) 40 | { 41 | GtkWidget *w, *s; 42 | 43 | /* get shared memory */ 44 | tabs = get_tabs (options.common_data.key, TRUE); 45 | if (!tabs) 46 | exit (-1); 47 | 48 | /* create widget */ 49 | paned = w = gtk_paned_new (options.paned_data.orient); 50 | gtk_widget_set_name (w, "yad-paned-widget"); 51 | 52 | s = gtk_socket_new (); 53 | gtk_widget_set_can_focus (s, TRUE); 54 | gtk_paned_add1 (GTK_PANED (w), s); 55 | g_object_set_data (G_OBJECT (w), "s1", s); 56 | 57 | s = gtk_socket_new (); 58 | gtk_widget_set_can_focus (s, TRUE); 59 | gtk_paned_add2 (GTK_PANED (w), s); 60 | g_object_set_data (G_OBJECT (w), "s2", s); 61 | 62 | return w; 63 | } 64 | 65 | void 66 | paned_swallow_childs (void) 67 | { 68 | GtkWidget *s1, *s2; 69 | 70 | s1 = GTK_WIDGET (g_object_get_data (G_OBJECT (paned), "s1")); 71 | s2 = GTK_WIDGET (g_object_get_data (G_OBJECT (paned), "s2")); 72 | 73 | /* wait until all children are registered */ 74 | while (!tabs[1].xid || !tabs[2].xid) 75 | usleep (1000); 76 | 77 | if (tabs[1].pid != -1) 78 | gtk_socket_add_id (GTK_SOCKET (s1), tabs[1].xid); 79 | if (tabs[2].pid != -1) 80 | gtk_socket_add_id (GTK_SOCKET (s2), tabs[2].xid); 81 | 82 | /* must be after embedding children */ 83 | if (options.paned_data.splitter > 0) 84 | gtk_paned_set_position (GTK_PANED (paned), options.paned_data.splitter); 85 | 86 | switch (options.paned_data.focused) 87 | { 88 | case 1: 89 | gtk_widget_child_focus (s1, GTK_DIR_TAB_FORWARD); 90 | break; 91 | case 2: 92 | gtk_widget_child_focus (s2, GTK_DIR_TAB_FORWARD); 93 | break; 94 | default: 95 | if (options.debug) 96 | g_printerr (_("WARNING: wrong focused pane number %d. Must be 1 or 2\n"), options.paned_data.focused); 97 | } 98 | } 99 | 100 | void 101 | paned_print_result (void) 102 | { 103 | if (tabs[1].pid != -1) 104 | kill (tabs[1].pid, SIGUSR1); 105 | if (tabs[2].pid != -1) 106 | kill (tabs[2].pid, SIGUSR1); 107 | } 108 | 109 | void 110 | paned_close_childs (void) 111 | { 112 | guint i; 113 | struct shmid_ds buf; 114 | gboolean is_running = TRUE; 115 | 116 | if (tabs[1].pid != -1) 117 | kill (tabs[1].pid, SIGUSR2); 118 | if (tabs[2].pid != -1) 119 | kill (tabs[2].pid, SIGUSR2); 120 | 121 | /* wait for stop subprocesses */ 122 | while (is_running) 123 | { 124 | is_running = FALSE; 125 | for (i = 1; i < 3; i++) 126 | { 127 | if (tabs[i].pid != -1 && kill (tabs[i].pid, 0) == 0) 128 | { 129 | is_running = TRUE; 130 | break; 131 | } 132 | } 133 | if (is_running) 134 | usleep (1000); 135 | } 136 | 137 | /* cleanup shared memory */ 138 | shmctl (tabs[0].pid, IPC_RMID, &buf); 139 | shmdt (tabs); 140 | } 141 | -------------------------------------------------------------------------------- /src/app.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include "yad.h" 21 | 22 | static GtkWidget *app; 23 | 24 | static void 25 | app_activated_cb (GtkAppChooserWidget *w, GAppInfo *app, gpointer d) 26 | { 27 | if (options.plug == -1) 28 | yad_exit (options.data.def_resp); 29 | } 30 | 31 | GtkWidget * 32 | app_create_widget (GtkWidget *dlg) 33 | { 34 | gchar *ctype; 35 | GtkWidget *w; 36 | 37 | if (options.extra_data && *options.extra_data) 38 | ctype = options.extra_data[0]; 39 | else 40 | ctype = "text/plain"; 41 | 42 | app = w = gtk_app_chooser_widget_new (ctype); 43 | gtk_widget_set_name (w, "yad-app-widget"); 44 | 45 | gtk_app_chooser_widget_set_show_default (GTK_APP_CHOOSER_WIDGET (w), TRUE); 46 | gtk_app_chooser_widget_set_show_recommended (GTK_APP_CHOOSER_WIDGET (w), TRUE); 47 | gtk_app_chooser_widget_set_show_fallback (GTK_APP_CHOOSER_WIDGET (w), options.app_data.show_fallback); 48 | gtk_app_chooser_widget_set_show_other (GTK_APP_CHOOSER_WIDGET (w), options.app_data.show_other); 49 | gtk_app_chooser_widget_set_show_all (GTK_APP_CHOOSER_WIDGET (w), options.app_data.show_all); 50 | 51 | g_signal_connect (G_OBJECT (w), "application-activated", G_CALLBACK (app_activated_cb), NULL); 52 | 53 | return w; 54 | } 55 | 56 | void 57 | app_print_result (void) 58 | { 59 | GAppInfo *info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (app)); 60 | 61 | if (info) 62 | { 63 | if (options.app_data.extended) 64 | { 65 | if (options.common_data.quoted_output) 66 | { 67 | gchar *buf; 68 | 69 | buf = g_shell_quote (g_app_info_get_name (info)); 70 | g_printf ("%s%s", buf, options.common_data.separator); 71 | g_free (buf); 72 | 73 | buf = g_shell_quote (g_app_info_get_display_name (info)); 74 | g_printf ("%s%s", buf, options.common_data.separator); 75 | g_free (buf); 76 | 77 | buf = g_shell_quote (g_app_info_get_description (info)); 78 | g_printf ("%s%s", buf, options.common_data.separator); 79 | g_free (buf); 80 | 81 | buf = g_shell_quote (g_icon_to_string (g_app_info_get_icon (info))); 82 | g_printf ("%s%s", buf, options.common_data.separator); 83 | g_free (buf); 84 | 85 | buf = g_shell_quote (g_app_info_get_executable (info)); 86 | g_printf ("%s%s", buf, options.common_data.separator); 87 | g_free (buf); 88 | 89 | g_printf ("\n"); 90 | } 91 | else 92 | { 93 | g_printf ("%s%s%s%s%s%s%s%s%s%s\n", 94 | g_app_info_get_name (info), options.common_data.separator, 95 | g_app_info_get_display_name (info), options.common_data.separator, 96 | g_app_info_get_description (info), options.common_data.separator, 97 | g_icon_to_string (g_app_info_get_icon (info)), options.common_data.separator, 98 | g_app_info_get_executable (info), options.common_data.separator); 99 | } 100 | } 101 | else 102 | { 103 | if (options.common_data.quoted_output) 104 | { 105 | gchar *buf = g_shell_quote (g_app_info_get_executable (info)); 106 | g_printf ("%s\n", buf); 107 | g_free (buf); 108 | } 109 | else 110 | g_printf ("%s\n", g_app_info_get_executable (info)); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/dnd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include "yad.h" 21 | 22 | static void 23 | drop_data_cb (GtkWidget * w, GdkDragContext * dc, gint x, gint y, 24 | GtkSelectionData * sel, guint info, guint t, gpointer data) 25 | { 26 | GdkAtom stgt; 27 | static guint drop_cnt = 0; 28 | 29 | stgt = gtk_selection_data_get_target (sel); 30 | 31 | if (gtk_targets_include_uri (&stgt, 1)) 32 | { 33 | gchar **uris; 34 | gint i = 0; 35 | 36 | uris = gtk_selection_data_get_uris (sel); 37 | if (!uris) 38 | return; 39 | 40 | while (uris[i]) 41 | { 42 | gchar *dstr = g_uri_unescape_string (uris[i], NULL); 43 | if (options.common_data.command) 44 | { 45 | gchar *action; 46 | 47 | if (g_strstr_len (options.common_data.command, -1, "%s")) 48 | action = g_strdup_printf (options.common_data.command, dstr); 49 | else 50 | action = g_strdup_printf ("%s '%s'", options.common_data.command, dstr); 51 | run_command_async (action); 52 | g_free (action); 53 | } 54 | else 55 | { 56 | g_printf ("%s\n", dstr); 57 | fflush (stdout); 58 | } 59 | g_free (dstr); 60 | i++; 61 | } 62 | g_strfreev (uris); 63 | } 64 | else if (gtk_targets_include_text (&stgt, 1)) 65 | { 66 | guchar *str = gtk_selection_data_get_text (sel); 67 | if (str) 68 | { 69 | gchar *dstr = g_uri_unescape_string ((const gchar *) str, NULL); 70 | if (options.common_data.command) 71 | { 72 | gchar *action, *arg; 73 | 74 | arg = g_shell_quote (dstr); 75 | if (g_strstr_len (options.common_data.command, -1, "%s")) 76 | action = g_strdup_printf (options.common_data.command, arg); 77 | else 78 | action = g_strdup_printf ("%s %s", options.common_data.command, arg); 79 | g_free (arg); 80 | 81 | run_command_async (action); 82 | g_free (action); 83 | } 84 | else 85 | { 86 | g_printf ("%s\n", dstr); 87 | fflush (stdout); 88 | } 89 | g_free (dstr); 90 | g_free (str); 91 | } 92 | } 93 | 94 | if (options.dnd_data.exit_on_drop) 95 | { 96 | drop_cnt++; 97 | if (drop_cnt == options.dnd_data.exit_on_drop) 98 | yad_exit (options.data.def_resp); 99 | } 100 | } 101 | 102 | void 103 | dnd_init (GtkWidget * w) 104 | { 105 | GtkTargetList *tlist; 106 | GtkTargetEntry *tgts; 107 | gint ntgts; 108 | 109 | tlist = gtk_target_list_new (NULL, 0); 110 | gtk_target_list_add_uri_targets (tlist, 0); 111 | gtk_target_list_add_text_targets (tlist, 0); 112 | 113 | tgts = gtk_target_table_new_from_list (tlist, &ntgts); 114 | 115 | gtk_drag_dest_set (w, GTK_DEST_DEFAULT_ALL, tgts, ntgts, GDK_ACTION_COPY | GDK_ACTION_MOVE); 116 | g_signal_connect (G_OBJECT (w), "drag_data_received", G_CALLBACK (drop_data_cb), NULL); 117 | 118 | gtk_target_table_free (tgts, ntgts); 119 | gtk_target_list_unref (tlist); 120 | 121 | /* set tooltip */ 122 | if (options.dnd_data.tooltip) 123 | { 124 | if (!options.data.no_markup) 125 | gtk_widget_set_tooltip_markup (w, options.data.dialog_text); 126 | else 127 | gtk_widget_set_tooltip_text (w, options.data.dialog_text); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /data/yad.gschema.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -1 13 |

Default width of dialog window 14 | 15 | 16 | -1 17 | Default height of dialog window 18 | 19 | 20 | 5 21 | Borders around dialog 22 | 23 | 24 | false 25 | Show remaining time and percentage in timeout progress bar 26 | 27 | 28 | false 29 | Combo-box in entry dialog is always editable 30 | 31 | 32 | 'xterm -e "%s"' 33 | Default terminal command (use %s for arguments placeholder) 34 | 35 | 36 | 'xdg-open "%s"' 37 | Default open command (use %s for arguments placeholder) 38 | 39 | 40 | '%x' 41 | Default date format (see strftime(3) for details) 42 | 43 | 44 | 'blue' 45 | Default color for URI in text-info dialog 46 | 47 | 48 | 100 49 | Maximum number of tabs in notebook dialog 50 | 51 | 52 | false 53 | Use large previews in file selection dialogs 54 | 55 | 56 | -1 57 | Set width of search entry in search bar 58 | 59 | 60 | true 61 | Ignore unknown command-line options 62 | 63 | 64 | false 65 | Enable debug mode with information about deprecated features 66 | 67 | 68 | 69 | 70 | 71 | '' 72 | Default color theme for text-info dialog 73 | 74 | 75 | false 76 | Show line numbers 77 | 78 | 79 | false 80 | Highlight current line 81 | 82 | 83 | false 84 | Enable line marks mode 85 | 86 | 87 | 'lightgreen' 88 | Default color for first type of text marks in text-info dialog 89 | 90 | 91 | 'pink' 92 | Default color for second type of text marks in text-info dialog 93 | 94 | 95 | 0 96 | Set right margin at position 97 | 98 | 99 | false 100 | Highlight matching brackets 101 | 102 | 103 | false 104 | Use autoindent 105 | 106 | 107 | 'never' 108 | Smart Home/End behavior 109 | 110 | 111 | false 112 | Use smart backspace 113 | 114 | 115 | 8 116 | Default tabulation width 117 | 118 | 119 | 4 120 | Default indentation width 121 | 122 | 123 | true 124 | Insert spaces instead of tabs 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /src/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include "yad.h" 21 | 22 | static GtkWidget *filechooser; 23 | 24 | static void 25 | file_activated_cb (GtkFileChooser * chooser, gpointer data) 26 | { 27 | if (options.plug == -1) 28 | yad_exit (options.data.def_resp); 29 | } 30 | 31 | gboolean 32 | file_confirm_overwrite (GtkWidget * dlg) 33 | { 34 | if (options.file_data.save && options.file_data.confirm_overwrite && !options.common_data.multi) 35 | { 36 | gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); 37 | 38 | if (g_file_test (filename, G_FILE_TEST_EXISTS)) 39 | return yad_confirm_dlg (GTK_WINDOW (dlg), options.file_data.confirm_text); 40 | } 41 | 42 | return TRUE; 43 | } 44 | 45 | GtkWidget * 46 | file_create_widget (GtkWidget * dlg) 47 | { 48 | GtkWidget *w; 49 | GList *filt; 50 | GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; 51 | 52 | if (options.file_data.directory) 53 | { 54 | if (options.file_data.save) 55 | action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; 56 | else 57 | action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; 58 | } 59 | else 60 | { 61 | if (options.file_data.save) 62 | action = GTK_FILE_CHOOSER_ACTION_SAVE; 63 | } 64 | 65 | w = filechooser = gtk_file_chooser_widget_new (action); 66 | gtk_widget_set_name (w, "yad-file-widget"); 67 | 68 | if (options.common_data.uri) 69 | { 70 | if (!options.file_data.directory && g_file_test (options.common_data.uri, G_FILE_TEST_IS_DIR)) 71 | gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), options.common_data.uri); 72 | else 73 | { 74 | gchar *dir = g_path_get_dirname (options.common_data.uri); 75 | 76 | if (g_path_is_absolute (options.common_data.uri) == TRUE) 77 | gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), dir); 78 | 79 | if (options.common_data.uri[strlen (options.common_data.uri) - 1] != '/') 80 | { 81 | gchar *basename = g_path_get_basename (options.common_data.uri); 82 | if (options.file_data.save) 83 | gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (w), basename); 84 | else 85 | gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), options.common_data.uri); 86 | g_free (basename); 87 | } 88 | g_free (dir); 89 | } 90 | } 91 | else 92 | gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), g_get_current_dir ()); 93 | 94 | if (options.common_data.multi) 95 | gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (w), TRUE); 96 | 97 | /* add preview */ 98 | if (options.common_data.preview) 99 | { 100 | GtkWidget *p = gtk_image_new (); 101 | gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (w), p); 102 | g_signal_connect (w, "update-preview", G_CALLBACK (update_preview), p); 103 | } 104 | 105 | /* add filters */ 106 | for (filt = options.common_data.filters; filt; filt = filt->next) 107 | gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (w), GTK_FILE_FILTER (filt->data)); 108 | 109 | g_signal_connect (w, "map", G_CALLBACK (gtk_file_chooser_set_show_hidden), GINT_TO_POINTER (options.common_data.show_hidden)); 110 | g_signal_connect (w, "file-activated", G_CALLBACK (file_activated_cb), dlg); 111 | 112 | return w; 113 | } 114 | 115 | void 116 | file_print_result (void) 117 | { 118 | GSList *selections, *iter; 119 | 120 | selections = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (filechooser)); 121 | for (iter = selections; iter != NULL; iter = iter->next) 122 | { 123 | if (options.common_data.quoted_output) 124 | { 125 | gchar *buf = g_shell_quote (g_filename_to_utf8 ((gchar *) iter->data, -1, NULL, NULL, NULL)); 126 | g_printf ("%s", buf); 127 | g_free (buf); 128 | } 129 | else 130 | g_printf ("%s", g_filename_to_utf8 ((gchar *) iter->data, -1, NULL, NULL, NULL)); 131 | g_free (iter->data); 132 | if (iter->next != NULL) 133 | g_printf ("%s", options.common_data.separator); 134 | } 135 | g_printf ("\n"); 136 | g_slist_free (selections); 137 | } 138 | -------------------------------------------------------------------------------- /src/about.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include "yad.h" 21 | 22 | static void 23 | yad_set_about_license (GtkWidget *dlg) 24 | { 25 | if (options.about_data.license == NULL) 26 | { 27 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_UNKNOWN); 28 | return; 29 | } 30 | 31 | gtk_about_dialog_set_wrap_license (GTK_ABOUT_DIALOG (dlg), TRUE); 32 | 33 | /* check for predefined */ 34 | if (strncmp (options.about_data.license, "GPL2", 4) == 0) 35 | { 36 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_GPL_2_0); 37 | return; 38 | } 39 | if (strncmp (options.about_data.license, "GPL3", 4) == 0) 40 | { 41 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_GPL_3_0); 42 | return; 43 | } 44 | if (strncmp (options.about_data.license, "LGPL2", 5) == 0) 45 | { 46 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_LGPL_2_1); 47 | return; 48 | } 49 | if (strncmp (options.about_data.license, "LGPL3", 5) == 0) 50 | { 51 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_LGPL_3_0); 52 | return; 53 | } 54 | if (strncmp (options.about_data.license, "BSD", 3) == 0) 55 | { 56 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_BSD); 57 | return; 58 | } 59 | if (strncmp (options.about_data.license, "MIT", 3) == 0) 60 | { 61 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_MIT_X11); 62 | return; 63 | } 64 | if (strncmp (options.about_data.license, "ARTISTIC", 8) == 0) 65 | { 66 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_ARTISTIC); 67 | return; 68 | } 69 | 70 | /* user specified */ 71 | gtk_about_dialog_set_license_type (GTK_ABOUT_DIALOG (dlg), GTK_LICENSE_CUSTOM); 72 | if (g_file_test (options.about_data.license, G_FILE_TEST_EXISTS)) 73 | { 74 | gchar *buf; 75 | 76 | if (g_file_get_contents (options.about_data.license, &buf, NULL, NULL)) 77 | { 78 | gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (dlg), buf); 79 | return; 80 | } 81 | } 82 | 83 | /* set as is */ 84 | gtk_about_dialog_set_license (GTK_ABOUT_DIALOG (dlg), options.about_data.license); 85 | 86 | return; 87 | } 88 | 89 | gint 90 | yad_about (void) 91 | { 92 | GtkWidget *dialog; 93 | 94 | const gchar *const authors[] = { 95 | "Victor Ananjevsky ", 96 | NULL 97 | }; 98 | const gchar *translators = N_("translator-credits"); 99 | 100 | gchar *comments = g_strdup_printf (_("Yet Another Dialog\n" 101 | "(show dialog boxes from shell scripts)\n" 102 | "\nBased on Zenity code\n\n" 103 | #ifdef HAVE_HTML 104 | "Built with Webkit\n" 105 | #endif 106 | #ifdef HAVE_SOURCEVIEW 107 | "Built with GtkSourceView\n" 108 | #endif 109 | #ifdef HAVE_SPELL 110 | "Built with GSpell\n" 111 | #endif 112 | "Using GTK+ %d.%d.%d\n"), 113 | gtk_major_version, gtk_minor_version, gtk_micro_version); 114 | 115 | dialog = gtk_about_dialog_new (); 116 | if (options.data.window_icon) 117 | gtk_window_set_icon_name (GTK_WINDOW (dialog), options.data.window_icon); 118 | else 119 | gtk_window_set_icon_name (GTK_WINDOW (dialog), "yad"); 120 | 121 | if (options.about_data.name != NULL) 122 | { 123 | /* custom about dialog */ 124 | gtk_about_dialog_set_program_name (GTK_ABOUT_DIALOG (dialog), options.about_data.name); 125 | if (options.data.dialog_image) 126 | gtk_about_dialog_set_logo (GTK_ABOUT_DIALOG (dialog), get_pixbuf (options.data.dialog_image, YAD_BIG_ICON, TRUE)); 127 | if (options.about_data.version) 128 | gtk_about_dialog_set_version (GTK_ABOUT_DIALOG (dialog), options.about_data.version); 129 | if (options.about_data.copyright) 130 | gtk_about_dialog_set_copyright (GTK_ABOUT_DIALOG (dialog), options.about_data.copyright); 131 | if (options.about_data.comments) 132 | gtk_about_dialog_set_comments (GTK_ABOUT_DIALOG (dialog), options.about_data.comments); 133 | if (options.about_data.authors) 134 | gtk_about_dialog_set_authors (GTK_ABOUT_DIALOG (dialog), (const gchar **) g_strsplit (options.about_data.authors, ",", -1)); 135 | if (options.about_data.website) 136 | gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (dialog), options.about_data.website); 137 | if (options.about_data.website_lbl) 138 | gtk_about_dialog_set_website_label (GTK_ABOUT_DIALOG (dialog), options.about_data.website_lbl); 139 | yad_set_about_license (dialog); 140 | } 141 | else 142 | { 143 | g_object_set (G_OBJECT (dialog), 144 | "name", PACKAGE_NAME, 145 | "version", PACKAGE_VERSION, 146 | "copyright", "Copyright \xc2\xa9 2008-2025, Victor Ananjevsky ", 147 | "comments", comments, 148 | "authors", authors, 149 | "website", PACKAGE_URL, 150 | "translator-credits", translators, 151 | "wrap-license", TRUE, 152 | "license-type", GTK_LICENSE_GPL_3_0, 153 | "logo-icon-name", "yad", 154 | NULL); 155 | } 156 | 157 | return gtk_dialog_run (GTK_DIALOG (dialog)); 158 | } 159 | -------------------------------------------------------------------------------- /src/notebook.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | #include "yad.h" 35 | 36 | static GtkWidget *notebook; 37 | static guint n_tabs = 0; 38 | 39 | static void 40 | stack_switch_cb (GObject *obj, GParamSpec *p, gpointer d) 41 | { 42 | GtkWidget *s = gtk_stack_get_visible_child (GTK_STACK (notebook)); 43 | gtk_widget_child_focus (s, GTK_DIR_TAB_FORWARD); 44 | } 45 | 46 | static void 47 | notebook_switch_cb (GtkNotebook *nb, GtkWidget *s, guint pn, gpointer d) 48 | { 49 | gtk_widget_child_focus (s, GTK_DIR_TAB_FORWARD); 50 | } 51 | 52 | GtkWidget * 53 | notebook_create_widget (GtkWidget * dlg) 54 | { 55 | GtkWidget *w; 56 | guint i; 57 | 58 | /* get shared memory */ 59 | tabs = get_tabs (options.common_data.key, TRUE); 60 | if (!tabs) 61 | exit (-1); 62 | 63 | /* create widget */ 64 | if (options.notebook_data.stack) 65 | { 66 | GtkWidget *ss; 67 | 68 | w = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); 69 | 70 | notebook = gtk_stack_new (); 71 | gtk_widget_set_name (notebook, "yad-stack-widget"); 72 | gtk_stack_set_homogeneous (GTK_STACK (notebook), TRUE); 73 | 74 | ss = gtk_stack_switcher_new (); 75 | gtk_widget_set_name (ss, "yad-stack-switcher-widget"); 76 | gtk_box_set_homogeneous (GTK_BOX (ss), options.notebook_data.expand); 77 | gtk_stack_switcher_set_stack (GTK_STACK_SWITCHER (ss), GTK_STACK (notebook)); 78 | 79 | if (options.notebook_data.pos == GTK_POS_BOTTOM) 80 | { 81 | gtk_box_pack_start (GTK_BOX (w), notebook, TRUE, TRUE, 2); 82 | gtk_box_pack_start (GTK_BOX (w), ss, FALSE, FALSE, 2); 83 | } 84 | else 85 | { 86 | gtk_box_pack_start (GTK_BOX (w), ss, FALSE, FALSE, 2); 87 | gtk_box_pack_start (GTK_BOX (w), notebook, TRUE, TRUE, 2); 88 | } 89 | 90 | gtk_widget_set_halign (ss, GTK_ALIGN_CENTER); 91 | } 92 | else 93 | { 94 | w = notebook = gtk_notebook_new (); 95 | gtk_widget_set_name (w, "yad-notebook-widget"); 96 | gtk_notebook_set_tab_pos (GTK_NOTEBOOK (w), options.notebook_data.pos); 97 | } 98 | 99 | /* add tabs */ 100 | for (i = 0; options.notebook_data.tabs[i] != NULL; i++) 101 | { 102 | GtkWidget *s; 103 | 104 | s = gtk_socket_new (); 105 | gtk_widget_set_margin_start (s, options.notebook_data.borders); 106 | gtk_widget_set_margin_end (s, options.notebook_data.borders); 107 | gtk_widget_set_margin_top (s, options.notebook_data.borders); 108 | gtk_widget_set_margin_bottom (s, options.notebook_data.borders); 109 | gtk_widget_set_can_focus (s, TRUE); 110 | 111 | if (options.notebook_data.stack) 112 | gtk_stack_add_titled (GTK_STACK (notebook), s, options.notebook_data.tabs[i], options.notebook_data.tabs[i]); 113 | else 114 | { 115 | gtk_notebook_append_page (GTK_NOTEBOOK (w), s, get_label (options.notebook_data.tabs[i], 0, NULL)); 116 | gtk_container_child_set (GTK_CONTAINER (w), s, "tab-expand", options.notebook_data.expand, NULL); 117 | } 118 | } 119 | n_tabs = i; 120 | 121 | return w; 122 | } 123 | 124 | void 125 | notebook_swallow_childs (void) 126 | { 127 | guint i; 128 | gboolean all_registered; 129 | GtkWidget *s; 130 | 131 | /* wait until all children are registered */ 132 | do 133 | { 134 | all_registered = TRUE; 135 | for (i = 1; i <= n_tabs; i++) 136 | if (!tabs[i].xid) 137 | { 138 | all_registered = FALSE; 139 | break; 140 | } 141 | if (!all_registered) 142 | usleep (1000); 143 | } 144 | while (!all_registered); 145 | 146 | for (i = 1; i <= n_tabs; i++) 147 | { 148 | if (options.notebook_data.stack) 149 | s = gtk_stack_get_child_by_name (GTK_STACK (notebook), options.notebook_data.tabs[i - 1]); 150 | else 151 | s = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i - 1); 152 | 153 | if (tabs[i].pid != -1 && s) 154 | gtk_socket_add_id (GTK_SOCKET (s), tabs[i].xid); 155 | } 156 | 157 | /* add signal handler for passing focus to a child */ 158 | if (options.notebook_data.stack) 159 | g_signal_connect (G_OBJECT (notebook), "notify::visible-child", G_CALLBACK (stack_switch_cb), NULL); 160 | else 161 | g_signal_connect (G_OBJECT (notebook), "switch-page", G_CALLBACK (notebook_switch_cb), NULL); 162 | 163 | /* set active tab */ 164 | if (options.notebook_data.active > 0) 165 | { 166 | if (options.notebook_data.stack) 167 | { 168 | s = gtk_stack_get_child_by_name (GTK_STACK (notebook), options.notebook_data.tabs[options.notebook_data.active - 1]); 169 | gtk_stack_set_visible_child (GTK_STACK (notebook), s); 170 | } 171 | else 172 | gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), options.notebook_data.active - 1); 173 | } 174 | } 175 | 176 | void 177 | notebook_print_result (void) 178 | { 179 | guint i; 180 | 181 | for (i = 1; i <= n_tabs; i++) 182 | { 183 | if (tabs[i].pid != -1) 184 | kill (tabs[i].pid, SIGUSR1); 185 | } 186 | } 187 | 188 | void 189 | notebook_close_childs (void) 190 | { 191 | guint i; 192 | struct shmid_ds buf; 193 | gboolean is_running; 194 | 195 | for (i = 1; i <= n_tabs; i++) 196 | { 197 | if (tabs[i].pid != -1) 198 | kill (tabs[i].pid, SIGUSR2); 199 | else 200 | break; 201 | } 202 | 203 | /* wait for stop subprocesses */ 204 | do 205 | { 206 | is_running = FALSE; 207 | for (i = 1; i <= n_tabs; i++) 208 | { 209 | if (tabs[i].pid != -1 && kill (tabs[i].pid, 0) == 0) 210 | { 211 | is_running = TRUE; 212 | break; 213 | } 214 | } 215 | if (is_running) 216 | usleep (1000); 217 | } 218 | while (is_running); 219 | 220 | /* cleanup shared memory */ 221 | shmctl (tabs[0].pid, IPC_RMID, &buf); 222 | shmdt (tabs); 223 | } 224 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([YAD], [14.90], [https://github.com/v1cont/yad/issues/], yad, [https://github.com/v1cont/yad/]) 2 | AC_CONFIG_AUX_DIR([build]) 3 | 4 | AM_INIT_AUTOMAKE([1.11 foreign dist-xz no-dist-gzip]) 5 | AM_SILENT_RULES([yes]) 6 | 7 | AC_PREREQ([2.59]) 8 | 9 | AC_CONFIG_HEADERS([config.h]) 10 | AC_CONFIG_SRCDIR([src]) 11 | 12 | AM_MAINTAINER_MODE 13 | 14 | AC_PROG_CC 15 | 16 | AC_PATH_PROG([ENV], [env]) 17 | 18 | PKG_CHECK_MODULES([GTK], [gtk+-3.0 >= 3.22.0 gtk+-unix-print-3.0]) 19 | AC_SUBST([GTK_CFLAGS]) 20 | AC_SUBST([GTK_LIBS]) 21 | 22 | dnl rgb.txt 23 | AC_ARG_WITH([rgb], 24 | [AS_HELP_STRING([--with-rgb=PATH], 25 | [set path to rgb.txt file (default - /etc/X11/rgb.txt)])], 26 | [with_rgb=$withval], [with_rgb=/etc/X11/rgb.txt]) 27 | AC_DEFINE_UNQUOTED([RGB_FILE], ["$with_rgb"], [Path to rgb.txt file]) 28 | 29 | dnl html widget 30 | AC_ARG_ENABLE([html], 31 | [AS_HELP_STRING([--enable-html], 32 | [Build YAD with HTML widget])], 33 | [build_html=$enableval], [build_html=yes]) 34 | if test x$build_html = xyes; then 35 | PKG_CHECK_MODULES([HTML], [webkit2gtk-4.1], [have_html=yes], [have_html=no]) 36 | if test x$have_html = xno; then 37 | PKG_CHECK_MODULES([HTML], [webkit2gtk-4.0], [have_html=yes], [have_html=no]) 38 | fi 39 | else 40 | have_html=no 41 | fi 42 | AC_SUBST([HTML_CFLAGS]) 43 | AC_SUBST([HTML_LIBS]) 44 | AM_CONDITIONAL([HTML], [test x$have_html = xyes]) 45 | 46 | if test x$have_html = xyes; then 47 | AC_DEFINE([HAVE_HTML], [1], [Define this if you have webkit2gt library]) 48 | fi 49 | 50 | dnl status icon widget 51 | AC_ARG_ENABLE([tray], 52 | [AS_HELP_STRING([--enable-tray], 53 | [Build YAD with status icon])], 54 | [build_tray=$enableval], [build_tray=yes]) 55 | AM_CONDITIONAL([TRAY], [test x$build_tray = xyes]) 56 | 57 | if test x$build_tray = xyes; then 58 | AC_DEFINE([HAVE_TRAY], [1], [Define this if you need status icon]) 59 | fi 60 | 61 | dnl appindicator support for modern desktop environments 62 | AC_ARG_ENABLE([appindicator], 63 | [AS_HELP_STRING([--enable-appindicator], 64 | [Build YAD with AppIndicator support (StatusNotifier/SNI)])], 65 | [build_appindicator=$enableval], [build_appindicator=auto]) 66 | if test x$build_appindicator != xno; then 67 | dnl Try ayatana-appindicator first (recommended), then fallback to legacy appindicator 68 | PKG_CHECK_MODULES([APPINDICATOR], [ayatana-appindicator3-0.1], [have_appindicator=yes], [have_appindicator=no]) 69 | if test x$have_appindicator = xno; then 70 | PKG_CHECK_MODULES([APPINDICATOR], [appindicator3-0.1], [have_appindicator=yes], [have_appindicator=no]) 71 | fi 72 | else 73 | have_appindicator=no 74 | fi 75 | AC_SUBST([APPINDICATOR_CFLAGS]) 76 | AC_SUBST([APPINDICATOR_LIBS]) 77 | AM_CONDITIONAL([APPINDICATOR], [test x$have_appindicator = xyes]) 78 | 79 | if test x$have_appindicator = xyes; then 80 | AC_DEFINE([HAVE_APPINDICATOR], [1], [Define this if you have AppIndicator support]) 81 | fi 82 | 83 | 84 | dnl spell check 85 | AC_ARG_ENABLE([spell], 86 | [AS_HELP_STRING([--enable-spell], 87 | [Build YAD with Spell check support (default - yes)])], 88 | [with_spell=$enableval], [with_spell=yes]) 89 | if test x$with_spell = xyes; then 90 | PKG_CHECK_MODULES([SPELL], [gspell-1], [have_spell=yes], [have_spell=no]) 91 | else 92 | have_spell=no 93 | fi 94 | AC_SUBST([SPELL_CFLAGS]) 95 | AC_SUBST([SPELL_LIBS]) 96 | 97 | if test x$have_spell = xyes; then 98 | AC_DEFINE([HAVE_SPELL], [1], [Define this if you need spell check support]) 99 | fi 100 | 101 | dnl sourceview 102 | AC_ARG_ENABLE([sourceview], 103 | [AS_HELP_STRING([--enable-sourceview], 104 | [Build YAD with GtkSourceView support (default - yes)])], 105 | [with_sourceview=$enableval], [with_sourceview=yes]) 106 | if test x$with_sourceview = xyes; then 107 | PKG_CHECK_MODULES([SOURCEVIEW], [gtksourceview-3.0 >= 3.18.0], [have_sourceview=yes], [have_sourceview=no]) 108 | else 109 | have_sourceview=no 110 | fi 111 | AC_SUBST([SOURCEVIEW_CFLAGS]) 112 | AC_SUBST([SOURCEVIEW_LIBS]) 113 | 114 | if test x$have_sourceview = xyes; then 115 | AC_DEFINE([HAVE_SOURCEVIEW], [1], [Define this if you need GtkSourceView support]) 116 | fi 117 | 118 | dnl standalone build 119 | AC_ARG_ENABLE([standalone], 120 | [AS_HELP_STRING([--enable-standalone], 121 | [Build standalone YAD binary (without gsettings)])], 122 | [build_sa=$enableval], [build_sa=no]) 123 | AM_CONDITIONAL([STANDALONE], [test x$build_sa = xyes]) 124 | 125 | if test x$build_sa = xyes; then 126 | AC_DEFINE([STANDALONE], [1], [Define this if you need standalone YAD binary]) 127 | fi 128 | 129 | dnl deprecated options 130 | AC_ARG_ENABLE([deprecated], 131 | [AS_HELP_STRING([--enable-deprecated], 132 | [Build YAD with deprecated options])], 133 | [build_depr=$enableval], [build_depr=yes]) 134 | 135 | if test x$build_depr = xyes; then 136 | AC_DEFINE([DEPRECATED], [1], [Define this if you need to build YAD with deprecated options]) 137 | fi 138 | 139 | dnl tools 140 | AC_ARG_ENABLE([tools], 141 | [AS_HELP_STRING([--enable-tools], 142 | [Build yad-tools utility])], 143 | [build_tools=$enableval], [build_tools=yes]) 144 | AM_CONDITIONAL([BUILD_TOOLS], [test x$build_tools = xyes]) 145 | 146 | dnl icon browser 147 | AC_ARG_ENABLE([icon-browser], 148 | [AS_HELP_STRING([--enable-icon-browser], 149 | [Build YAD icon browser])], 150 | [build_ib=$enableval], [build_ib=yes]) 151 | AM_CONDITIONAL([BUILD_IB], [test x$build_ib = xyes]) 152 | 153 | # GSettings 154 | GLIB_GSETTINGS 155 | 156 | AC_SEARCH_LIBS(round, m) 157 | 158 | # ******************************* 159 | # Internationalization 160 | # ******************************* 161 | 162 | GETTEXT_PACKAGE=yad 163 | AC_SUBST([GETTEXT_PACKAGE]) 164 | AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext domain]) 165 | 166 | AM_GNU_GETTEXT_VERSION([0.19.7]) 167 | AM_GNU_GETTEXT([external]) 168 | 169 | # ******************************* 170 | 171 | AC_SUBST([AM_CFLAGS]) 172 | AC_SUBST([AM_CPPFLAGS]) 173 | AC_SUBST([AM_LDFLAGS]) 174 | 175 | # ******************************* 176 | 177 | AC_CONFIG_LINKS([ 178 | src/yad-settings.sh:src/yad-settings.in 179 | ]) 180 | 181 | AC_CONFIG_FILES([ 182 | Makefile 183 | po/Makefile.in 184 | src/Makefile 185 | src/yad-settings 186 | data/Makefile 187 | data/icons/Makefile 188 | data/icons/16x16/Makefile 189 | data/icons/24x24/Makefile 190 | data/icons/32x32/Makefile 191 | data/icons/48x48/Makefile 192 | data/icons/96x96/Makefile 193 | data/icons/128x128/Makefile 194 | data/yad.m4 195 | data/yad.spec 196 | ]) 197 | 198 | AC_OUTPUT 199 | 200 | echo 201 | echo "Build configuratioh:" 202 | echo " Status icon - $build_tray" 203 | echo " HTML widget - $have_html" 204 | echo " GtkSourceView - $have_sourceview" 205 | echo " Spell checking - $have_spell" 206 | echo " Tray widget - $build_tray" 207 | echo " Appindicator - $have_appindicator" 208 | echo " Path to rgb.txt - $with_rgb" 209 | echo " Standalone build - $build_sa" 210 | echo " Deprecated options - $build_depr" 211 | echo " Tools - $build_tools" 212 | echo " Icon browser - $build_ib" 213 | echo 214 | -------------------------------------------------------------------------------- /src/scale.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include "yad.h" 21 | #include 22 | 23 | enum { 24 | PLUS_BTN = 0, 25 | MINUS_BTN, 26 | }; 27 | 28 | static GtkAdjustment *adj; 29 | static GtkWidget *scale; 30 | static GtkWidget *plus_btn = NULL; 31 | static GtkWidget *minus_btn = NULL; 32 | 33 | static void 34 | value_changed_cb (GtkWidget * w, gpointer data) 35 | { 36 | if (options.scale_data.enforce_step) 37 | { 38 | /* Make sure the new value corresponds to a step in the range. */ 39 | gdouble value = gtk_adjustment_get_value ((GtkAdjustment *)adj); 40 | gdouble new_value = (gdouble) round(value/options.scale_data.step) * options.scale_data.step; 41 | gtk_adjustment_set_value ((GtkAdjustment *)adj, new_value); 42 | } 43 | 44 | if (options.scale_data.print_partial) 45 | g_print ("%.0f\n", gtk_range_get_value (GTK_RANGE (scale))); 46 | 47 | if (options.scale_data.buttons) 48 | { 49 | gdouble v = gtk_range_get_value (GTK_RANGE (scale)); 50 | 51 | if (v >= options.scale_data.max_value) 52 | gtk_widget_set_sensitive (plus_btn, FALSE); 53 | else 54 | gtk_widget_set_sensitive (plus_btn, TRUE); 55 | 56 | if (v <= options.scale_data.min_value) 57 | gtk_widget_set_sensitive (minus_btn, FALSE); 58 | else 59 | gtk_widget_set_sensitive (minus_btn, TRUE); 60 | } 61 | } 62 | 63 | static void 64 | vb_pressed (GtkWidget *b, gpointer data) 65 | { 66 | gdouble v, cv = gtk_range_get_value (GTK_RANGE (scale)); 67 | 68 | switch (GPOINTER_TO_INT (data)) 69 | { 70 | case PLUS_BTN: 71 | v = cv + options.scale_data.step; 72 | gtk_range_set_value (GTK_RANGE (scale), MIN (v, options.scale_data.max_value)); 73 | break; 74 | case MINUS_BTN: 75 | v = cv - options.scale_data.step; 76 | gtk_range_set_value (GTK_RANGE (scale), MAX (v, options.scale_data.min_value)); 77 | break; 78 | } 79 | } 80 | 81 | GtkWidget * 82 | scale_create_widget (GtkWidget * dlg) 83 | { 84 | GtkWidget *w; 85 | gint page; 86 | 87 | if (options.scale_data.min_value >= options.scale_data.max_value) 88 | { 89 | g_printerr (_("Maximum value must be greater than minimum value.\n")); 90 | return NULL; 91 | } 92 | 93 | /* check for initial value */ 94 | if (options.scale_data.have_value) 95 | { 96 | if (options.scale_data.value < options.scale_data.min_value) 97 | { 98 | g_printerr (_("Initial value less than minimal.\n")); 99 | options.scale_data.value = options.scale_data.min_value; 100 | } 101 | else if (options.scale_data.value > options.scale_data.max_value) 102 | { 103 | g_printerr (_("Initial value greater than maximum.\n")); 104 | options.scale_data.value = options.scale_data.max_value; 105 | } 106 | } 107 | else 108 | options.scale_data.value = options.scale_data.min_value; 109 | 110 | page = options.scale_data.page == -1 ? options.scale_data.step * 10 : options.scale_data.page; 111 | /* this type conversion needs only for gtk-2.0 */ 112 | adj = (GtkAdjustment *) gtk_adjustment_new ((double) options.scale_data.value, 113 | (double) options.scale_data.min_value, 114 | (double) options.scale_data.max_value, 115 | (double) options.scale_data.step, 116 | (double) page, 117 | 0.0); 118 | if (options.common_data.vertical) 119 | { 120 | scale = gtk_scale_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (adj)); 121 | gtk_range_set_inverted (GTK_RANGE (scale), !options.scale_data.invert); 122 | } 123 | else 124 | { 125 | scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (adj)); 126 | gtk_range_set_inverted (GTK_RANGE (scale), options.scale_data.invert); 127 | } 128 | gtk_widget_set_name (scale, "yad-scale-widget"); 129 | gtk_scale_set_digits (GTK_SCALE (scale), 0); 130 | 131 | if (options.scale_data.hide_value) 132 | gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE); 133 | 134 | /* add marks */ 135 | if (options.scale_data.marks) 136 | { 137 | GtkPositionType pos; 138 | GSList *m = options.scale_data.marks; 139 | 140 | pos = options.common_data.vertical ? GTK_POS_LEFT : GTK_POS_BOTTOM; 141 | for (; m; m = m->next) 142 | { 143 | YadScaleMark *mark = (YadScaleMark *) m->data; 144 | gtk_scale_add_mark (GTK_SCALE (scale), mark->value, pos, mark->name); 145 | } 146 | } 147 | 148 | /* create container */ 149 | if (options.common_data.vertical) 150 | w = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1); 151 | else 152 | w = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1); 153 | 154 | /* create buttons */ 155 | if (options.scale_data.buttons) 156 | { 157 | minus_btn = gtk_button_new_with_label ("-"); 158 | gtk_button_set_relief (GTK_BUTTON (minus_btn), GTK_RELIEF_NONE); 159 | g_signal_connect (G_OBJECT (minus_btn), "clicked", G_CALLBACK (vb_pressed), GINT_TO_POINTER (MINUS_BTN)); 160 | gtk_widget_set_sensitive (minus_btn, (options.scale_data.value > options.scale_data.min_value)); 161 | 162 | plus_btn = gtk_button_new_with_label ("+"); 163 | gtk_button_set_relief (GTK_BUTTON (plus_btn), GTK_RELIEF_NONE); 164 | g_signal_connect (G_OBJECT (plus_btn), "clicked", G_CALLBACK (vb_pressed), GINT_TO_POINTER (PLUS_BTN)); 165 | gtk_widget_set_sensitive (plus_btn, (options.scale_data.value < options.scale_data.max_value)); 166 | } 167 | 168 | /* create complex widget */ 169 | if (options.scale_data.buttons) 170 | gtk_box_pack_start (GTK_BOX (w), options.common_data.vertical ? plus_btn : minus_btn, FALSE, FALSE, 0); 171 | 172 | gtk_box_pack_start (GTK_BOX (w), scale, TRUE, TRUE, 2); 173 | 174 | if (options.scale_data.buttons) 175 | gtk_box_pack_start (GTK_BOX (w), options.common_data.vertical ? minus_btn : plus_btn, FALSE, FALSE, 0); 176 | 177 | g_signal_connect (G_OBJECT (scale), "value-changed", G_CALLBACK (value_changed_cb), NULL); 178 | gtk_widget_grab_focus (scale); 179 | 180 | return w; 181 | } 182 | 183 | void 184 | scale_print_result (void) 185 | { 186 | g_print ("%.0f\n", gtk_range_get_value (GTK_RANGE (scale))); 187 | } 188 | -------------------------------------------------------------------------------- /src/yad-settings.in: -------------------------------------------------------------------------------- 1 | #! @ENV@ bash 2 | # -*- mode: sh -*- 3 | # 4 | # YAD settings editor. This file is part of YAD 5 | # 6 | # YAD is free software: you can redistribute it and/or modify it under 7 | # the terms of the GNU General Public License as published by the Free Software 8 | # Foundation, either version 3 of the License, or (at your option) any later 9 | # version. 10 | # 11 | # YAD is distributed in the hope that it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License along with 16 | # YAD. If not, see . 17 | # 18 | # Copyright (C) 2021-2025, Victor Ananjevsky 19 | # 20 | 21 | TEXTDOMAIN=@GETTEXT_PACKAGE@ 22 | TEXTDOMAINDIR=@prefix@/share/locale 23 | 24 | res1=$(mktemp --tmpdir ys-tab1.XXXXXXXX) 25 | res2=$(mktemp --tmpdir ys-tab2.XXXXXXXX) 26 | trap "rm -f $res1 $res2" EXIT 27 | 28 | KEY=$RANDOM 29 | 30 | # first tab (values at the end due to possible hyphens) 31 | yad --plug=$KEY --tabnum=1 --bool-fmt=t --quoted-output --separator=" " \ 32 | --form --scroll --homogeneous \ 33 | --text=$"Main YAD settings and default values\n\n" \ 34 | --field=$"Width of dialog window::NUM" \ 35 | --field=$"Height of dialog window::NUM" \ 36 | --field=$"Border width around dialog::NUM" \ 37 | --field=$"Show remaining time and percentage in timeout progress bar:CHK" \ 38 | --field=$"Combo-box in entry dialog is always editable:CHK" \ 39 | --field=$"Default terminal command:" \ 40 | --field=$"Default open command:" \ 41 | --field=$"Default date format:" \ 42 | --field=$"Default URI color in text-info dialog::CLR" \ 43 | --field=$"Maximum number of tabs in notebook dialog::NUM" \ 44 | --field=$"Use large previews in file selection dialogs:CHK" \ 45 | --field=$"Search entry width::NUM" \ 46 | --field=$"Ignore unknown command-line options:CHK" \ 47 | --field=$"Enable debug mode with information about deprecated features:CHK" \ 48 | -- \ 49 | "$(gsettings get yad.settings width)!-1..32767" \ 50 | "$(gsettings get yad.settings height)!-1..32767" \ 51 | $(gsettings get yad.settings border) \ 52 | $(gsettings get yad.settings show-remain) \ 53 | $(gsettings get yad.settings combo-always-editable) \ 54 | "$(eval echo $(gsettings get yad.settings terminal))" \ 55 | "$(eval echo $(gsettings get yad.settings open-command))" \ 56 | "$(eval echo $(gsettings get yad.settings date-format))" \ 57 | "$(eval echo $(gsettings get yad.settings uri-color))" \ 58 | $(gsettings get yad.settings max-tab) \ 59 | $(gsettings get yad.settings large-preview) \ 60 | $(gsettings get yad.settings search-width) \ 61 | $(gsettings get yad.settings ignore-unknown-options) \ 62 | $(gsettings get yad.settings debug) > $res1 & 63 | 64 | # get list for themes 65 | eval SV_THEME=$(gsettings get yad.sourceview theme) 66 | themes=$"!" 67 | while read t; do 68 | [[ $t == $SV_THEME ]] && themes+="^$t!" || themes+="$t!" 69 | done < <(yad-tools --show-themes) 70 | 71 | # get list for home/end 72 | eval HE=$(gsettings get yad.sourceview homend) 73 | for b in never before after always; do 74 | [[ $b == $HE ]] && homend+="^$b!" || homend+="$b!" 75 | done 76 | 77 | # second tab 78 | yad --plug=$KEY --tabnum=2 --bool-fmt=t --quoted-output --separator=" " --form --scroll \ 79 | --text=$"YAD settings for text editor\nThis settings only usefull when YAD built with GtkSourceView\n\n" \ 80 | --field=$"Default theme for text-info dialog::CB" "${themes%?}" \ 81 | --field=$"Show line numbers:CHK" $(gsettings get yad.sourceview line-num) \ 82 | --field=$"Hightlight current line:CHK" $(gsettings get yad.sourceview line-hl) \ 83 | --field=$"Enable line marks mode:CHK" $(gsettings get yad.sourceview line-marks) \ 84 | --field=$"Color of first type marks::CLR" "$(eval echo $(gsettings get yad.sourceview mark1-color))" \ 85 | --field=$"Color of second type marks::CLR" "$(eval echo $(gsettings get yad.sourceview mark2-color))" \ 86 | --field=$"Right margin position::NUM" $(gsettings get yad.sourceview right-margin) \ 87 | --field=$"Highlight matching brackets:CHK" $(gsettings get yad.sourceview brackets) \ 88 | --field=$"Use autoindentation:CHK" $(gsettings get yad.sourceview indent) \ 89 | --field=$"Smart Home/End behavior::CB" "${homend%?}" \ 90 | --field=$"Use smart backspace:CHK" $(gsettings get yad.sourceview smart-bs) \ 91 | --field=$"Tabulation width::NUM" $(gsettings get yad.sourceview tab-width) \ 92 | --field=$"Indentation width::NUM" $(gsettings get yad.sourceview indent-width) \ 93 | --field=$"Insert spaces instead of tabulation:CHK" $(gsettings get yad.sourceview spaces) > $res2 & 94 | 95 | # main dialog 96 | yad --title=$"YAD settings" --key=$KEY --width=600 --height=700 --image=preferences-other \ 97 | --button=$"Load defaults!view-refresh:3" --button="yad-save:0" --button="yad-close:1" \ 98 | --text=$"YAD settings editor" --text-align=center \ 99 | --notebook --stack --expand --tab=$"Main" --tab=$"Editor" 100 | 101 | if [[ $? -eq 0 ]]; then 102 | eval r1=($(< $res1)) 103 | eval r2=($(< $res2)) 104 | 105 | # Main settings 106 | gsettings set yad.settings width ${r1[0]} 107 | gsettings set yad.settings height ${r1[1]} 108 | gsettings set yad.settings border ${r1[2]} 109 | gsettings set yad.settings show-remain ${r1[3]} 110 | gsettings set yad.settings combo-always-editable ${r1[4]} 111 | gsettings set yad.settings terminal "${r1[5]}" 112 | gsettings set yad.settings open-command "${r1[6]}" 113 | gsettings set yad.settings date-format "${r1[7]}" 114 | gsettings set yad.settings uri-color ${r1[8]} 115 | gsettings set yad.settings max-tab ${r1[9]} 116 | gsettings set yad.settings large-preview ${r1[10]} 117 | gsettings set yad.settings search-width ${r1[11]} 118 | gsettings set yad.settings ignore-unknown-options ${r1[12]} 119 | gsettings set yad.settings debug ${r1[13]} 120 | 121 | # GtkSourceView settings 122 | gsettings set yad.sourceview theme "${r2[0]}" 123 | gsettings set yad.sourceview line-num ${r2[1]} 124 | gsettings set yad.sourceview line-hl ${r2[2]} 125 | gsettings set yad.sourceview line-marks ${r2[3]} 126 | gsettings set yad.sourceview mark1-color ${r2[4]} 127 | gsettings set yad.sourceview mark2-color ${r2[5]} 128 | gsettings set yad.sourceview right-margin ${r2[6]} 129 | gsettings set yad.sourceview brackets ${r2[7]} 130 | gsettings set yad.sourceview indent ${r2[8]} 131 | gsettings set yad.sourceview homend ${r2[9]} 132 | gsettings set yad.sourceview smart-bs ${r2[10]} 133 | gsettings set yad.sourceview tab-width ${r2[11]} 134 | gsettings set yad.sourceview indent-width ${r2[12]} 135 | gsettings set yad.sourceview spaces ${r2[13]} 136 | elif [[ $? -eq 3 ]]; then 137 | # Load default settings 138 | gsettings reset-recursively yad.settings 139 | gsettings reset-recursively yad.sourceview 140 | fi 141 | -------------------------------------------------------------------------------- /src/color.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | 22 | #include "yad.h" 23 | #include "cpicker.h" 24 | 25 | static GtkWidget *color; 26 | 27 | static GtkTreeModel * 28 | create_palette () 29 | { 30 | FILE *fp; 31 | gchar *filename; 32 | gchar buf[1024], *name; 33 | GtkListStore *store; 34 | GdkPixbuf *pb; 35 | GtkTreeIter iter; 36 | 37 | gchar *cxpm[] = { 38 | "16 14 1 1", 39 | ". c #FFFFFF", 40 | "................", 41 | "................", 42 | "................", 43 | "................", 44 | "................", 45 | "................", 46 | "................", 47 | "................", 48 | "................", 49 | "................", 50 | "................", 51 | "................", 52 | "................", 53 | "................" 54 | }; 55 | gchar cl[] = ". c #FFFFFF"; 56 | 57 | if (options.color_data.palette) 58 | filename = options.color_data.palette; 59 | else 60 | filename = RGB_FILE; 61 | 62 | if ((fp = fopen (filename, "r")) == NULL) 63 | { 64 | g_printerr (_("Can't open file %s: %s\n"), filename, strerror (errno)); 65 | return NULL; 66 | } 67 | 68 | store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); 69 | 70 | while ((name = fgets (buf, sizeof (buf), fp)) != NULL) 71 | { 72 | gint r, g, b; 73 | gchar spec[8]; 74 | 75 | if (buf[0] == '!') 76 | continue; 77 | 78 | sscanf (buf, "%d %d %d", &r, &g, &b); 79 | 80 | g_sprintf (spec, "#%.2X%.2X%.2X", r, g, b); 81 | g_sprintf (cl, ". c #%.2X%.2X%.2X", r, g, b); 82 | cxpm[1] = cl; 83 | pb = gdk_pixbuf_new_from_xpm_data ((const gchar **) cxpm); 84 | 85 | while (g_ascii_isdigit (*name) || g_ascii_isspace (*name)) 86 | name++; 87 | 88 | gtk_list_store_append (store, &iter); 89 | gtk_list_store_set (store, &iter, 0, pb, 1, spec, 2, g_strstrip (name), -1); 90 | } 91 | 92 | fclose (fp); 93 | 94 | return GTK_TREE_MODEL (store); 95 | } 96 | 97 | static void 98 | set_color (gchar *clr) 99 | { 100 | GdkRGBA c; 101 | if (gdk_rgba_parse (&c, clr)) 102 | gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color), &c); 103 | } 104 | 105 | static void 106 | picker_clicked (GtkWidget *w, gpointer data) 107 | { 108 | yad_get_screen_color (color); 109 | } 110 | 111 | static void 112 | palette_changed (GtkTreeSelection * sel, gpointer data) 113 | { 114 | GtkTreeModel *model; 115 | GtkTreeIter iter; 116 | 117 | if (gtk_tree_selection_get_selected (sel, &model, &iter)) 118 | { 119 | gchar *clr; 120 | gtk_tree_model_get (model, &iter, 1, &clr, -1); 121 | set_color (clr); 122 | } 123 | } 124 | 125 | GtkWidget * 126 | color_create_widget (GtkWidget * dlg) 127 | { 128 | GtkWidget *w; 129 | 130 | w = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); 131 | color = gtk_color_chooser_widget_new (); 132 | gtk_widget_set_name (color, "yad-color-widget"); 133 | g_object_set (G_OBJECT (color), "show-editor", !options.color_data.gtk_palette, NULL); 134 | 135 | if (options.color_data.init_color) 136 | set_color (options.color_data.init_color); 137 | gtk_box_pack_start (GTK_BOX (w), color, FALSE, FALSE, 2); 138 | 139 | if (options.color_data.color_picker) 140 | { 141 | GtkWidget *b, *i; 142 | 143 | b = gtk_button_new_with_label (_("Pick up screen color")); 144 | 145 | i = gtk_image_new_from_icon_name ("gtk-color-picker", GTK_ICON_SIZE_BUTTON); 146 | gtk_button_set_image (GTK_BUTTON (b), i); 147 | g_object_set (G_OBJECT (b), "always-show-image", TRUE, NULL); 148 | 149 | g_signal_connect (G_OBJECT (b), "clicked", G_CALLBACK (picker_clicked), NULL); 150 | 151 | gtk_box_pack_start (GTK_BOX (w), b, FALSE, FALSE, 2); 152 | } 153 | 154 | if (options.color_data.use_palette) 155 | { 156 | GtkTreeModel *model; 157 | 158 | if ((model = create_palette ()) != NULL) 159 | { 160 | GtkWidget *exp, *sw, *list; 161 | GtkCellRenderer *r; 162 | GtkTreeViewColumn *col; 163 | GtkTreeSelection *sel; 164 | 165 | /* create expander */ 166 | exp = gtk_expander_new (_("Palette")); 167 | gtk_expander_set_expanded (GTK_EXPANDER (exp), options.color_data.expand_palette); 168 | gtk_container_set_border_width (GTK_CONTAINER (exp), 5); 169 | gtk_box_pack_start (GTK_BOX (w), exp, TRUE, TRUE, 2); 170 | 171 | /* create color list */ 172 | sw = gtk_scrolled_window_new (NULL, NULL); 173 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); 174 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.data.hscroll_policy, options.data.vscroll_policy); 175 | gtk_widget_set_size_request (sw, -1, 75); 176 | gtk_container_add (GTK_CONTAINER (exp), sw); 177 | gtk_widget_set_vexpand (sw, TRUE); 178 | list = gtk_tree_view_new_with_model (model); 179 | gtk_widget_set_name (list, "yad-color-palette"); 180 | g_object_unref (model); 181 | gtk_container_add (GTK_CONTAINER (sw), list); 182 | 183 | /* add first columns */ 184 | col = gtk_tree_view_column_new (); 185 | gtk_tree_view_column_set_title (col, _("Color")); 186 | 187 | /* pixbuf */ 188 | r = gtk_cell_renderer_pixbuf_new (); 189 | gtk_tree_view_column_pack_start (col, r, FALSE); 190 | gtk_tree_view_column_set_attributes (col, r, "pixbuf", 0, NULL); 191 | 192 | /* color value */ 193 | r = gtk_cell_renderer_text_new (); 194 | gtk_tree_view_column_pack_start (col, r, TRUE); 195 | gtk_tree_view_column_set_attributes (col, r, "text", 1, NULL); 196 | 197 | gtk_tree_view_column_set_sort_column_id (col, 1); 198 | gtk_tree_view_append_column (GTK_TREE_VIEW (list), col); 199 | 200 | /* add second column */ 201 | r = gtk_cell_renderer_text_new (); 202 | col = gtk_tree_view_column_new_with_attributes (_("Name"), r, "text", 2, NULL); 203 | gtk_tree_view_column_set_sort_column_id (col, 2); 204 | gtk_tree_view_append_column (GTK_TREE_VIEW (list), col); 205 | 206 | /* enable searching on Name column */ 207 | gtk_tree_view_set_search_column (GTK_TREE_VIEW (list), 2); 208 | 209 | /* setup the selection handler */ 210 | sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); 211 | gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE); 212 | g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (palette_changed), NULL); 213 | 214 | gtk_widget_show_all (exp); 215 | } 216 | } 217 | 218 | return w; 219 | } 220 | 221 | void 222 | color_print_result (void) 223 | { 224 | GdkRGBA c; 225 | gchar *cs; 226 | 227 | gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (color), &c); 228 | cs = get_color (&c); 229 | 230 | if (cs) 231 | g_printf ("%s\n", cs); 232 | } 233 | -------------------------------------------------------------------------------- /src/cpicker.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2020-2025, Victor Ananjevsky 18 | */ 19 | 20 | /* This code getted from deprecated GtkColorSelection widget (gtk+-3.24.33) */ 21 | 22 | #define GDK_DISABLE_DEPRECATION_WARNINGS 23 | 24 | #include "cpicker.h" 25 | 26 | #define BIG_STEP 20 27 | 28 | typedef struct { 29 | GtkWidget *color_widget; 30 | GtkWidget *grab_widget; 31 | GdkDevice *keyb_device; 32 | GdkDevice *pointer_device; 33 | gboolean has_grab; 34 | guint32 time; 35 | } GrabData; 36 | 37 | static gboolean key_press (GtkWidget * invisible, GdkEventKey * event, gpointer data); 38 | static gboolean mouse_press (GtkWidget * invisible, GdkEventButton * event, gpointer data); 39 | 40 | static GdkCursor * 41 | make_picker_cursor (GdkScreen * screen) 42 | { 43 | GdkDisplay *display; 44 | GdkCursor *cursor; 45 | 46 | display = gdk_screen_get_display (screen); 47 | cursor = gdk_cursor_new_from_name (display, "color-picker"); 48 | if (!cursor) 49 | cursor = gdk_cursor_new_from_name (display, "cell"); 50 | if (!cursor) 51 | g_printerr ("cpicker: cannot create cursor\n"); 52 | return cursor; 53 | } 54 | 55 | static void 56 | grab_color_at_pointer (GdkScreen * screen, GdkDevice * device, gint x_root, gint y_root, gpointer data) 57 | { 58 | GdkPixbuf *pixbuf; 59 | guchar *pixels; 60 | GdkRGBA color; 61 | GdkWindow *root_window = gdk_screen_get_root_window (screen); 62 | GrabData *gd = (GrabData *) data; 63 | 64 | pixbuf = gdk_pixbuf_get_from_window (root_window, x_root, y_root, 1, 1); 65 | if (!pixbuf) 66 | { 67 | gint x, y; 68 | GdkWindow *window = gdk_device_get_window_at_position (device, &x, &y); 69 | if (!window) 70 | return; 71 | pixbuf = gdk_pixbuf_get_from_window (window, x, y, 1, 1); 72 | if (!pixbuf) 73 | return; 74 | } 75 | pixels = gdk_pixbuf_get_pixels (pixbuf); 76 | color.red = pixels[0] / 255.; 77 | color.green = pixels[1] / 255.; 78 | color.blue = pixels[2] / 255.; 79 | color.alpha = 1.0; 80 | g_object_unref (pixbuf); 81 | 82 | if (gd->color_widget) 83 | gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (gd->color_widget), &color); 84 | else 85 | g_print ("#%02X%02X%02X\n", (gint) (color.red * 255), (gint) (color.green * 255), (gint) (color.blue * 255)); 86 | } 87 | 88 | static void 89 | shutdown_eyedropper (gpointer data) 90 | { 91 | GrabData *gd = (GrabData *) data; 92 | 93 | if (gd->has_grab) 94 | { 95 | gdk_device_ungrab (gd->keyb_device, gd->time); 96 | gdk_device_ungrab (gd->pointer_device, gd->time); 97 | gtk_device_grab_remove (gd->grab_widget, gd->pointer_device); 98 | } 99 | 100 | if (gd->color_widget == NULL) 101 | gtk_main_quit (); 102 | } 103 | 104 | static void 105 | mouse_motion (GtkWidget * invisible, GdkEventMotion * event, gpointer data) 106 | { 107 | grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event), 108 | gdk_event_get_device ((GdkEvent *) event), event->x_root, event->y_root, data); 109 | } 110 | 111 | static gboolean 112 | mouse_release (GtkWidget * invisible, GdkEventButton * event, gpointer data) 113 | { 114 | /* GtkColorSelection *colorsel = data; */ 115 | 116 | if (event->button != GDK_BUTTON_PRIMARY) 117 | return FALSE; 118 | 119 | grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event), 120 | gdk_event_get_device ((GdkEvent *) event), event->x_root, event->y_root, data); 121 | 122 | shutdown_eyedropper (data); 123 | 124 | g_signal_handlers_disconnect_by_func (invisible, mouse_motion, data); 125 | g_signal_handlers_disconnect_by_func (invisible, mouse_release, data); 126 | 127 | return TRUE; 128 | } 129 | 130 | /* Helper Functions */ 131 | 132 | static gboolean 133 | key_press (GtkWidget * invisible, GdkEventKey * event, gpointer data) 134 | { 135 | GdkScreen *screen = gdk_event_get_screen ((GdkEvent *) event); 136 | GdkDevice *device, *pointer_device; 137 | guint state = event->state & gtk_accelerator_get_default_mod_mask (); 138 | gint x, y, dx, dy; 139 | 140 | device = gdk_event_get_device ((GdkEvent *) event); 141 | pointer_device = gdk_device_get_associated_device (device); 142 | gdk_device_get_position (pointer_device, NULL, &x, &y); 143 | 144 | dx = dy = 0; 145 | 146 | switch (event->keyval) 147 | { 148 | case GDK_KEY_space: 149 | case GDK_KEY_Return: 150 | case GDK_KEY_ISO_Enter: 151 | case GDK_KEY_KP_Enter: 152 | case GDK_KEY_KP_Space: 153 | grab_color_at_pointer (screen, pointer_device, x, y, data); 154 | /* fall through */ 155 | 156 | case GDK_KEY_Escape: 157 | shutdown_eyedropper (data); 158 | 159 | g_signal_handlers_disconnect_by_func (invisible, mouse_press, data); 160 | g_signal_handlers_disconnect_by_func (invisible, key_press, data); 161 | 162 | return TRUE; 163 | 164 | case GDK_KEY_Up: 165 | case GDK_KEY_KP_Up: 166 | dy = state == GDK_MOD1_MASK ? -BIG_STEP : -1; 167 | break; 168 | 169 | case GDK_KEY_Down: 170 | case GDK_KEY_KP_Down: 171 | dy = state == GDK_MOD1_MASK ? BIG_STEP : 1; 172 | break; 173 | 174 | case GDK_KEY_Left: 175 | case GDK_KEY_KP_Left: 176 | dx = state == GDK_MOD1_MASK ? -BIG_STEP : -1; 177 | break; 178 | 179 | case GDK_KEY_Right: 180 | case GDK_KEY_KP_Right: 181 | dx = state == GDK_MOD1_MASK ? BIG_STEP : 1; 182 | break; 183 | 184 | default: 185 | return FALSE; 186 | } 187 | 188 | gdk_device_warp (pointer_device, screen, x + dx, y + dy); 189 | 190 | return TRUE; 191 | } 192 | 193 | static gboolean 194 | mouse_press (GtkWidget * invisible, GdkEventButton * event, gpointer data) 195 | { 196 | if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) 197 | { 198 | g_signal_connect (invisible, "motion-notify-event", G_CALLBACK (mouse_motion), data); 199 | g_signal_connect (invisible, "button-release-event", G_CALLBACK (mouse_release), data); 200 | g_signal_handlers_disconnect_by_func (invisible, mouse_press, data); 201 | g_signal_handlers_disconnect_by_func (invisible, key_press, data); 202 | return TRUE; 203 | } 204 | 205 | return FALSE; 206 | } 207 | 208 | void 209 | yad_get_screen_color (GtkWidget *widget) 210 | { 211 | GrabData *gd; 212 | GdkScreen *screen; 213 | GdkDevice *device; 214 | GdkCursor *picker_cursor; 215 | GdkGrabStatus grab_status; 216 | GdkWindow *window; 217 | 218 | gd = g_new0 (GrabData, 1); 219 | gd->color_widget = widget; 220 | gd->time = gtk_get_current_event_time (); 221 | 222 | screen = gdk_screen_get_default (); 223 | device = gtk_get_current_event_device (); 224 | 225 | if (device) 226 | { 227 | if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) 228 | { 229 | gd->keyb_device = device; 230 | gd->pointer_device = gdk_device_get_associated_device (device); 231 | } 232 | else 233 | { 234 | gd->pointer_device = device; 235 | gd->keyb_device = gdk_device_get_associated_device (device); 236 | } 237 | } 238 | else 239 | { 240 | GdkSeat *seat = gdk_display_get_default_seat (gdk_screen_get_display (screen)); 241 | gd->keyb_device = gdk_seat_get_keyboard (seat); 242 | gd->pointer_device = gdk_seat_get_pointer (seat); 243 | } 244 | 245 | gd->grab_widget = gtk_window_new (GTK_WINDOW_POPUP); 246 | gtk_window_set_screen (GTK_WINDOW (gd->grab_widget), screen); 247 | gtk_window_resize (GTK_WINDOW (gd->grab_widget), 1, 1); 248 | gtk_window_move (GTK_WINDOW (gd->grab_widget), -100, -100); 249 | gtk_widget_show (gd->grab_widget); 250 | 251 | gtk_widget_add_events (gd->grab_widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); 252 | 253 | window = gtk_widget_get_window (gd->grab_widget); 254 | if (gdk_device_grab (gd->keyb_device, window, GDK_OWNERSHIP_APPLICATION, FALSE, 255 | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, gd->time) != GDK_GRAB_SUCCESS) 256 | return; 257 | 258 | picker_cursor = make_picker_cursor (screen); 259 | grab_status = gdk_device_grab (gd->pointer_device, window, GDK_OWNERSHIP_APPLICATION, FALSE, 260 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK, 261 | picker_cursor, gd->time); 262 | if (picker_cursor) 263 | g_object_unref (picker_cursor); 264 | 265 | if (grab_status != GDK_GRAB_SUCCESS) 266 | { 267 | gdk_device_ungrab (gd->keyb_device, gd->time); 268 | return; 269 | } 270 | 271 | gtk_device_grab_add (gd->grab_widget, gd->pointer_device, TRUE); 272 | 273 | gd->has_grab = TRUE; 274 | 275 | g_signal_connect (gd->grab_widget, "button-press-event", G_CALLBACK (mouse_press), gd); 276 | g_signal_connect (gd->grab_widget, "key-press-event", G_CALLBACK (key_press), gd); 277 | } 278 | -------------------------------------------------------------------------------- /src/entry.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include "yad.h" 21 | 22 | static GtkWidget *entry; 23 | static gboolean is_combo = FALSE; 24 | 25 | static void 26 | entry_activate_cb (GtkEntry * entry, gpointer data) 27 | { 28 | if (options.plug == -1) 29 | yad_exit (options.data.def_resp); 30 | } 31 | 32 | static gboolean 33 | combo_activate_cb (GtkWidget * w, GdkEventKey * ev, gpointer data) 34 | { 35 | if (ev->keyval == GDK_KEY_Return || ev->keyval == GDK_KEY_KP_Enter) 36 | { 37 | if (options.plug == -1) 38 | yad_exit (options.data.def_resp); 39 | return TRUE; 40 | } 41 | return FALSE; 42 | } 43 | 44 | static void 45 | icon_cb (GtkEntry * entry, GtkEntryIconPosition pos, GdkEventButton * event, gpointer data) 46 | { 47 | if (event->button == 1) 48 | { 49 | gchar *cmd = NULL; 50 | 51 | switch (pos) 52 | { 53 | case GTK_ENTRY_ICON_PRIMARY: 54 | cmd = options.entry_data.licon_action; 55 | break; 56 | case GTK_ENTRY_ICON_SECONDARY: 57 | cmd = options.entry_data.ricon_action; 58 | break; 59 | } 60 | 61 | if (cmd) 62 | { 63 | FILE *pf; 64 | gchar buf[1024]; 65 | GString *str; 66 | 67 | str = g_string_new (""); 68 | pf = popen (cmd, "r"); 69 | while (fgets (buf, sizeof (buf), pf)) 70 | g_string_append (str, buf); 71 | if (pclose (pf) == 0) 72 | { 73 | if (str->str[str->len - 1] == '\n') 74 | str->str[str->len - 1] = '\0'; 75 | gtk_entry_set_text (GTK_ENTRY (entry), str->str); 76 | } 77 | g_string_free (str, TRUE); 78 | } 79 | else 80 | gtk_entry_set_text (GTK_ENTRY (entry), ""); 81 | 82 | /* move cursor to the end of text */ 83 | gtk_editable_set_position (GTK_EDITABLE (entry), -1); 84 | } 85 | } 86 | 87 | static GtkTreeModel * 88 | create_completion_model (void) 89 | { 90 | GtkListStore *store; 91 | GtkTreeIter iter; 92 | gint i = 0; 93 | 94 | store = gtk_list_store_new (1, G_TYPE_STRING); 95 | 96 | if (options.extra_data) 97 | { 98 | while (options.extra_data[i] != NULL) 99 | { 100 | gtk_list_store_append (store, &iter); 101 | gtk_list_store_set (store, &iter, 0, options.extra_data[i], -1); 102 | i++; 103 | } 104 | } 105 | 106 | return GTK_TREE_MODEL (store); 107 | } 108 | 109 | GtkWidget * 110 | entry_create_widget (GtkWidget * dlg) 111 | { 112 | GtkWidget *c, *l = NULL, *w = NULL; 113 | 114 | w = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); 115 | 116 | if (options.entry_data.entry_label) 117 | { 118 | l = gtk_label_new (NULL); 119 | if (options.data.no_markup) 120 | gtk_label_set_text_with_mnemonic (GTK_LABEL (l), options.entry_data.entry_label); 121 | else 122 | gtk_label_set_markup_with_mnemonic (GTK_LABEL (l), options.entry_data.entry_label); 123 | gtk_widget_set_name (l, "yad-entry-label"); 124 | gtk_box_pack_start (GTK_BOX (w), l, FALSE, FALSE, 1); 125 | } 126 | 127 | if (options.entry_data.numeric) 128 | { 129 | gdouble min, max, step, val; 130 | guint prec; 131 | 132 | min = 0.0; 133 | max = 65535.0; 134 | step = 1.0; 135 | prec = 0; 136 | val = 0.0; 137 | 138 | if (options.extra_data && options.extra_data[0]) 139 | { 140 | min = g_ascii_strtod (options.extra_data[0], NULL); 141 | if (options.extra_data[1]) 142 | { 143 | max = g_ascii_strtod (options.extra_data[1], NULL); 144 | if (options.extra_data[2]) 145 | { 146 | step = g_ascii_strtod (options.extra_data[2], NULL); 147 | if (options.extra_data[3]) 148 | { 149 | prec = (guint) g_ascii_strtoull (options.extra_data[3], NULL, 0); 150 | if (prec > 20) 151 | prec = 20; 152 | } 153 | } 154 | } 155 | } 156 | 157 | c = entry = gtk_spin_button_new_with_range (min, max, step); 158 | gtk_entry_set_alignment (GTK_ENTRY (c), 1.0); 159 | gtk_spin_button_set_digits (GTK_SPIN_BUTTON (c), prec); 160 | gtk_widget_set_name (entry, "yad-entry-spin"); 161 | 162 | if (options.entry_data.entry_text) 163 | { 164 | val = g_ascii_strtod (options.entry_data.entry_text, NULL); 165 | 166 | if (min >= max) 167 | { 168 | g_printerr (_("Maximum value must be greater than minimum value.\n")); 169 | min = 0.0; 170 | max = 65535.0; 171 | } 172 | 173 | if (val < min) 174 | { 175 | g_printerr (_("Initial value less than minimal.\n")); 176 | val = min; 177 | } 178 | else if (val > max) 179 | { 180 | g_printerr (_("Initial value greater than maximum.\n")); 181 | val = max; 182 | } 183 | } 184 | 185 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (c), val); 186 | } 187 | else if (!options.entry_data.completion && options.extra_data && *options.extra_data) 188 | { 189 | gint active, i; 190 | 191 | if (options.common_data.editable || 192 | #ifndef STANDALONE 193 | g_settings_get_boolean (settings, "combo-always-editable") 194 | #else 195 | COMBO_ALWAYS_EDIT 196 | #endif 197 | ) 198 | { 199 | c = gtk_combo_box_text_new_with_entry (); 200 | gtk_widget_set_name (c, "yad-entry-edit-combo"); 201 | entry = gtk_bin_get_child (GTK_BIN (c)); 202 | if (options.entry_data.licon) 203 | { 204 | GdkPixbuf *pb = get_pixbuf (options.entry_data.licon, YAD_SMALL_ICON, TRUE); 205 | 206 | if (pb) 207 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, pb); 208 | } 209 | if (options.entry_data.ricon) 210 | { 211 | GdkPixbuf *pb = get_pixbuf (options.entry_data.ricon, YAD_SMALL_ICON, TRUE); 212 | 213 | if (pb) 214 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, pb); 215 | } 216 | } 217 | else 218 | { 219 | c = entry = gtk_combo_box_text_new (); 220 | gtk_widget_set_name (c, "yad-entry-combo"); 221 | is_combo = TRUE; 222 | } 223 | 224 | i = 0; 225 | active = -1; 226 | while (options.extra_data[i] != NULL) 227 | { 228 | if (options.entry_data.entry_text && 229 | g_ascii_strcasecmp (options.extra_data[i], options.entry_data.entry_text) == 0) 230 | active = i; 231 | gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (c), options.extra_data[i]); 232 | i++; 233 | } 234 | 235 | if (options.entry_data.entry_text && active == -1) 236 | gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (c), options.entry_data.entry_text); 237 | 238 | /* set first iter active */ 239 | if (!options.common_data.editable) 240 | gtk_combo_box_set_active (GTK_COMBO_BOX (c), (active != -1 ? active : 0)); 241 | } 242 | else 243 | { 244 | c = entry = gtk_entry_new (); 245 | gtk_widget_set_name (c, "yad-entry-widget"); 246 | 247 | gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); 248 | 249 | if (options.entry_data.entry_text) 250 | gtk_entry_set_text (GTK_ENTRY (entry), options.entry_data.entry_text); 251 | 252 | if (options.common_data.hide_text) 253 | g_object_set (G_OBJECT (entry), "visibility", FALSE, NULL); 254 | 255 | if (options.entry_data.completion) 256 | { 257 | GtkEntryCompletion *completion; 258 | GtkTreeModel *completion_model; 259 | 260 | completion = gtk_entry_completion_new (); 261 | gtk_entry_set_completion (GTK_ENTRY (entry), completion); 262 | 263 | completion_model = create_completion_model (); 264 | gtk_entry_completion_set_model (completion, completion_model); 265 | g_object_unref (completion_model); 266 | 267 | gtk_entry_completion_set_text_column (completion, 0); 268 | 269 | if (options.common_data.complete != YAD_COMPLETE_SIMPLE) 270 | gtk_entry_completion_set_match_func (completion, check_complete, NULL, NULL); 271 | 272 | g_object_unref (completion); 273 | } 274 | 275 | if (options.entry_data.licon) 276 | { 277 | GdkPixbuf *pb = get_pixbuf (options.entry_data.licon, YAD_SMALL_ICON, TRUE); 278 | 279 | if (pb) 280 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, pb); 281 | } 282 | if (options.entry_data.ricon) 283 | { 284 | GdkPixbuf *pb = get_pixbuf (options.entry_data.ricon, YAD_SMALL_ICON, TRUE); 285 | 286 | if (pb) 287 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, pb); 288 | } 289 | } 290 | 291 | if (l) 292 | gtk_label_set_mnemonic_widget (GTK_LABEL (l), entry); 293 | 294 | if (!is_combo) 295 | g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (entry_activate_cb), dlg); 296 | else 297 | g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK (combo_activate_cb), dlg); 298 | 299 | if (options.entry_data.licon || options.entry_data.ricon) 300 | g_signal_connect (G_OBJECT (entry), "icon-press", G_CALLBACK (icon_cb), NULL); 301 | 302 | gtk_box_pack_start (GTK_BOX (w), c, TRUE, TRUE, 1); 303 | 304 | return w; 305 | } 306 | 307 | void 308 | entry_print_result (void) 309 | { 310 | if (options.entry_data.numeric) 311 | { 312 | guint prec = gtk_spin_button_get_digits (GTK_SPIN_BUTTON (entry)); 313 | g_print ("%.*f\n", prec, gtk_spin_button_get_value (GTK_SPIN_BUTTON (entry))); 314 | } 315 | else if (is_combo) 316 | { 317 | if (options.common_data.num_output) 318 | g_print ("%d\n", gtk_combo_box_get_active (GTK_COMBO_BOX (entry)) + 1); 319 | else 320 | g_print ("%s\n", gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (entry))); 321 | } 322 | else 323 | g_print ("%s\n", gtk_entry_get_text (GTK_ENTRY (entry))); 324 | } 325 | -------------------------------------------------------------------------------- /src/appindicator.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | /* 21 | * AppIndicator/StatusNotifier support for modern desktop environments. 22 | * This is a separate dialog type from the legacy GtkStatusIcon notification. 23 | * 24 | * This module provides system tray functionality using the StatusNotifier 25 | * specification (D-Bus based) which is supported by KDE Plasma, GNOME 26 | * (with extensions), and other modern desktop environments. 27 | */ 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "yad.h" 36 | 37 | /* Try Ayatana AppIndicator first (recommended), fall back to legacy */ 38 | #if __has_include() 39 | #include 40 | #elif __has_include() 41 | #include 42 | #else 43 | #error "AppIndicator support enabled but headers not found" 44 | #endif 45 | 46 | typedef struct { 47 | gchar *name; 48 | gchar *action; 49 | gchar *icon; 50 | } MenuData; 51 | 52 | static AppIndicator *app_indicator = NULL; 53 | static GtkWidget *indicator_menu = NULL; 54 | 55 | static gchar *icon = NULL; 56 | static gchar *action = NULL; 57 | 58 | static GSList *menu_data = NULL; 59 | 60 | static gint exit_code; 61 | 62 | static void 63 | free_menu_data (gpointer data) 64 | { 65 | MenuData *m = (MenuData *) data; 66 | 67 | if (m) { 68 | g_free (m->name); 69 | g_free (m->action); 70 | g_free (m->icon); 71 | g_free (m); 72 | } 73 | } 74 | 75 | static void 76 | parse_menu_str (gchar *str) 77 | { 78 | gchar **menu_vals; 79 | gint i = 0; 80 | 81 | if (menu_data) 82 | { 83 | g_slist_free_full (menu_data, free_menu_data); 84 | menu_data = NULL; 85 | } 86 | 87 | menu_vals = g_strsplit (str, options.common_data.separator, -1); 88 | 89 | while (menu_vals[i] != NULL) 90 | { 91 | MenuData *mdata = g_new0 (MenuData, 1); 92 | gchar **s = g_strsplit (menu_vals[i], options.common_data.item_separator, 3); 93 | 94 | if (s[0]) 95 | { 96 | YadStock sit; 97 | if (stock_lookup (s[0], &sit)) 98 | { 99 | mdata->name = g_strdup (sit.label); 100 | mdata->icon = g_strdup (sit.icon); 101 | } 102 | else 103 | mdata->name = g_strdup (s[0]); 104 | if (s[1]) 105 | { 106 | mdata->action = g_strdup (s[1]); 107 | if (s[2]) 108 | mdata->icon = g_strdup (s[2]); 109 | } 110 | } 111 | menu_data = g_slist_append (menu_data, mdata); 112 | g_strfreev (s); 113 | i++; 114 | } 115 | 116 | g_strfreev (menu_vals); 117 | } 118 | 119 | static void 120 | timeout_cb (gpointer data) 121 | { 122 | exit_code = YAD_RESPONSE_TIMEOUT; 123 | gtk_main_quit (); 124 | } 125 | 126 | static void 127 | set_icon (void) 128 | { 129 | const gchar *icon_name = icon ? icon : "yad"; 130 | 131 | if (app_indicator) 132 | { 133 | app_indicator_set_icon_full (app_indicator, icon_name, "YAD"); 134 | } 135 | } 136 | 137 | static void 138 | activate_cb (GtkMenuItem *item, gpointer data) 139 | { 140 | if ((action == NULL && !options.common_data.listen) || (action && g_ascii_strcasecmp (action, "quit") == 0)) 141 | { 142 | exit_code = YAD_RESPONSE_OK; 143 | gtk_main_quit (); 144 | } 145 | else if (action) 146 | { 147 | run_command_async (action); 148 | } 149 | } 150 | 151 | static void 152 | popup_menu_item_activate_cb (GtkWidget *w, gpointer data) 153 | { 154 | gchar *cmd = (gchar *) data; 155 | 156 | if (cmd) 157 | { 158 | if (g_ascii_strcasecmp (g_strstrip (cmd), "quit") == 0) 159 | { 160 | exit_code = YAD_RESPONSE_OK; 161 | gtk_main_quit (); 162 | } 163 | else 164 | run_command_async (cmd); 165 | } 166 | } 167 | 168 | static void 169 | build_indicator_menu (void) 170 | { 171 | GtkWidget *item; 172 | GSList *m; 173 | 174 | if (indicator_menu) 175 | gtk_widget_destroy (indicator_menu); 176 | 177 | indicator_menu = gtk_menu_new (); 178 | 179 | /* Add activate action as first item if action is set */ 180 | if (action && g_ascii_strcasecmp (action, "quit") != 0 && g_ascii_strcasecmp (action, "menu") != 0) 181 | { 182 | item = gtk_menu_item_new_with_label (_("Activate")); 183 | g_signal_connect (item, "activate", G_CALLBACK (activate_cb), NULL); 184 | gtk_menu_shell_append (GTK_MENU_SHELL (indicator_menu), item); 185 | 186 | item = gtk_separator_menu_item_new (); 187 | gtk_menu_shell_append (GTK_MENU_SHELL (indicator_menu), item); 188 | } 189 | 190 | /* Add custom menu items */ 191 | for (m = menu_data; m; m = m->next) 192 | { 193 | MenuData *d = (MenuData *) m->data; 194 | 195 | if (d->name) 196 | { 197 | GtkWidget *b, *i, *l; 198 | 199 | item = gtk_menu_item_new (); 200 | b = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); 201 | 202 | if (d->icon) 203 | { 204 | GdkPixbuf *pb = get_pixbuf (d->icon, YAD_SMALL_ICON, TRUE); 205 | if (pb) 206 | { 207 | i = gtk_image_new_from_pixbuf (pb); 208 | gtk_container_add (GTK_CONTAINER (b), i); 209 | g_object_unref (pb); 210 | } 211 | } 212 | l = gtk_label_new_with_mnemonic (d->name); 213 | gtk_label_set_xalign (GTK_LABEL (l), 0.0); 214 | gtk_label_set_mnemonic_widget (GTK_LABEL (l), item); 215 | gtk_box_pack_end (GTK_BOX (b), l, TRUE, TRUE, 0); 216 | 217 | gtk_container_add (GTK_CONTAINER (item), b); 218 | 219 | g_signal_connect (GTK_MENU_ITEM (item), "activate", 220 | G_CALLBACK (popup_menu_item_activate_cb), (gpointer) d->action); 221 | } 222 | else 223 | item = gtk_separator_menu_item_new (); 224 | 225 | gtk_menu_shell_append (GTK_MENU_SHELL (indicator_menu), item); 226 | } 227 | 228 | /* Add quit item */ 229 | item = gtk_separator_menu_item_new (); 230 | gtk_menu_shell_append (GTK_MENU_SHELL (indicator_menu), item); 231 | 232 | item = gtk_menu_item_new_with_label (_("Quit")); 233 | g_signal_connect (item, "activate", G_CALLBACK (popup_menu_item_activate_cb), "quit"); 234 | gtk_menu_shell_append (GTK_MENU_SHELL (indicator_menu), item); 235 | 236 | gtk_widget_show_all (indicator_menu); 237 | app_indicator_set_menu (app_indicator, GTK_MENU (indicator_menu)); 238 | } 239 | 240 | static gboolean 241 | handle_stdin (GIOChannel *channel, GIOCondition condition, gpointer data) 242 | { 243 | if ((condition & G_IO_IN) != 0) 244 | { 245 | GString *string; 246 | GError *err = NULL; 247 | 248 | string = g_string_new (NULL); 249 | while (channel->is_readable == FALSE) 250 | usleep (100); 251 | 252 | do 253 | { 254 | gint status; 255 | gchar *command = NULL, *value = NULL, **args; 256 | 257 | do 258 | { 259 | status = g_io_channel_read_line_string (channel, string, NULL, &err); 260 | 261 | while (gdk_events_pending ()) 262 | gtk_main_iteration (); 263 | } 264 | while (status == G_IO_STATUS_AGAIN); 265 | 266 | if (status != G_IO_STATUS_NORMAL) 267 | { 268 | if (err) 269 | { 270 | g_printerr ("yad_appindicator_handle_stdin(): %s\n", err->message); 271 | g_error_free (err); 272 | err = NULL; 273 | } 274 | /* stop handling but not exit */ 275 | g_io_channel_shutdown (channel, TRUE, NULL); 276 | return FALSE; 277 | } 278 | 279 | strip_new_line (string->str); 280 | if (!string->str[0]) 281 | continue; 282 | 283 | args = g_strsplit (string->str, ":", 2); 284 | command = g_strdup (args[0]); 285 | if (args[1]) 286 | value = g_strdup (args[1]); 287 | g_strfreev (args); 288 | if (value) 289 | g_strstrip (value); 290 | 291 | if (!g_ascii_strcasecmp (command, "icon") && value) 292 | { 293 | g_free (icon); 294 | icon = g_strdup (value); 295 | set_icon (); 296 | } 297 | else if (!g_ascii_strcasecmp (command, "tooltip")) 298 | { 299 | if (g_utf8_validate (value, -1, NULL)) 300 | { 301 | gchar *message = g_strcompress (value); 302 | app_indicator_set_title (app_indicator, message); 303 | g_free (message); 304 | } 305 | else 306 | g_printerr (_("Invalid UTF-8 in tooltip!\n")); 307 | } 308 | else if (!g_ascii_strcasecmp (command, "visible")) 309 | { 310 | if (!g_ascii_strcasecmp (value, "false")) 311 | app_indicator_set_status (app_indicator, APP_INDICATOR_STATUS_PASSIVE); 312 | else 313 | app_indicator_set_status (app_indicator, APP_INDICATOR_STATUS_ACTIVE); 314 | } 315 | else if (!g_ascii_strcasecmp (command, "action")) 316 | { 317 | g_free (action); 318 | action = NULL; 319 | if (value && *value) 320 | action = g_strdup (value); 321 | } 322 | else if (!g_ascii_strcasecmp (command, "quit")) 323 | { 324 | exit_code = YAD_RESPONSE_OK; 325 | gtk_main_quit (); 326 | } 327 | else if (!g_ascii_strcasecmp (command, "menu")) 328 | { 329 | if (value && *value) 330 | { 331 | parse_menu_str (value); 332 | build_indicator_menu (); 333 | } 334 | } 335 | else 336 | g_printerr (_("Unknown command '%s'\n"), command); 337 | 338 | g_free (command); 339 | g_free (value); 340 | } 341 | while (g_io_channel_get_buffer_condition (channel) == G_IO_IN); 342 | g_string_free (string, TRUE); 343 | } 344 | 345 | if ((condition & G_IO_HUP) != 0) 346 | { 347 | g_io_channel_shutdown (channel, TRUE, NULL); 348 | gtk_main_quit (); 349 | return FALSE; 350 | } 351 | 352 | return TRUE; 353 | } 354 | 355 | gint 356 | yad_appindicator_run (void) 357 | { 358 | GIOChannel *channel = NULL; 359 | 360 | if (options.data.dialog_image) 361 | icon = g_strdup (options.data.dialog_image); 362 | if (options.common_data.command) 363 | action = g_strdup (options.common_data.command); 364 | 365 | if (options.notification_data.menu) 366 | parse_menu_str (options.notification_data.menu); 367 | 368 | /* Create AppIndicator */ 369 | app_indicator = app_indicator_new ("yad-indicator", 370 | icon ? icon : "yad", 371 | APP_INDICATOR_CATEGORY_APPLICATION_STATUS); 372 | 373 | if (!app_indicator) 374 | { 375 | g_printerr (_("Failed to create AppIndicator\n")); 376 | return YAD_RESPONSE_CANCEL; 377 | } 378 | 379 | app_indicator_set_status (app_indicator, 380 | options.notification_data.hidden ? 381 | APP_INDICATOR_STATUS_PASSIVE : 382 | APP_INDICATOR_STATUS_ACTIVE); 383 | 384 | if (options.data.dialog_text) 385 | app_indicator_set_title (app_indicator, options.data.dialog_text); 386 | else 387 | app_indicator_set_title (app_indicator, _("Yad indicator")); 388 | 389 | set_icon (); 390 | 391 | /* Build menu - AppIndicator requires a menu */ 392 | build_indicator_menu (); 393 | 394 | if (options.debug) 395 | g_printerr (_("Using AppIndicator (StatusNotifier) backend.\n")); 396 | 397 | if (options.common_data.listen) 398 | { 399 | channel = g_io_channel_unix_new (0); 400 | if (channel) 401 | { 402 | g_io_channel_set_encoding (channel, NULL, NULL); 403 | g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); 404 | g_io_add_watch (channel, G_IO_IN | G_IO_HUP, handle_stdin, NULL); 405 | } 406 | } 407 | 408 | if (options.data.timeout > 0) 409 | g_timeout_add_seconds (options.data.timeout, (GSourceFunc) timeout_cb, NULL); 410 | 411 | gtk_main (); 412 | 413 | return exit_code; 414 | } 415 | 416 | -------------------------------------------------------------------------------- /src/browser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2010-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | typedef struct { 27 | GtkWidget *win; 28 | GtkWidget *image; 29 | GtkWidget *lname; 30 | GtkWidget *lsize; 31 | GtkWidget *lfile; 32 | GtkWidget *cat_list; 33 | GtkWidget *icon_list; 34 | 35 | GtkIconTheme *theme; 36 | 37 | GHashTable *icons; 38 | } IconBrowserData; 39 | 40 | static gboolean show_regular = TRUE; 41 | static gboolean show_symbolic = FALSE; 42 | 43 | static gboolean 44 | key_press_cb (GtkWidget * w, GdkEventKey * ev, gpointer data) 45 | { 46 | if (ev->keyval == GDK_KEY_Escape) 47 | { 48 | gtk_main_quit (); 49 | return TRUE; 50 | } 51 | return FALSE; 52 | } 53 | 54 | static GtkListStore * 55 | load_icon_cat (IconBrowserData * data, gchar * cat) 56 | { 57 | GtkListStore *store; 58 | GList *i, *icons; 59 | gint size, w, h; 60 | 61 | gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); 62 | size = MIN (w, h); 63 | 64 | store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING); 65 | 66 | icons = gtk_icon_theme_list_icons (data->theme, cat); 67 | for (i = icons; i; i = i->next) 68 | { 69 | GtkTreeIter iter; 70 | GdkPixbuf *pb, *spb; 71 | GtkIconInfo *info; 72 | 73 | info = gtk_icon_theme_lookup_icon (data->theme, i->data, size, 0); 74 | if (gtk_icon_info_is_symbolic (info)) 75 | { 76 | if (!show_symbolic) 77 | continue; 78 | } 79 | else 80 | { 81 | if (!show_regular) 82 | continue; 83 | } 84 | g_object_unref (info); 85 | 86 | spb = pb = gtk_icon_theme_load_icon (data->theme, i->data, size, 0, NULL); 87 | 88 | if (pb) 89 | { 90 | /* scale pixbuf if needed */ 91 | w = gdk_pixbuf_get_width (pb); 92 | h = gdk_pixbuf_get_height (pb); 93 | if (w > size || h > size) 94 | { 95 | pb = gdk_pixbuf_scale_simple (spb, size, size, GDK_INTERP_BILINEAR); 96 | g_object_unref (spb); 97 | } 98 | } 99 | 100 | gtk_list_store_append (store, &iter); 101 | gtk_list_store_set (store, &iter, 0, pb, 1, i->data, -1); 102 | 103 | if (pb) 104 | g_object_unref (pb); 105 | } 106 | g_list_free_full (icons, g_free); 107 | 108 | gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 1, GTK_SORT_ASCENDING); 109 | 110 | return store; 111 | } 112 | 113 | static void 114 | print_icon (GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, IconBrowserData *data) 115 | { 116 | GtkTreeModel *model; 117 | GtkTreeIter iter; 118 | gchar *icon; 119 | 120 | model = gtk_tree_view_get_model (tv); 121 | gtk_tree_model_get_iter (model, &iter, path); 122 | gtk_tree_model_get (model, &iter, 1, &icon, -1); 123 | 124 | g_print ("%s\n", icon); 125 | 126 | gtk_main_quit (); 127 | } 128 | 129 | static void 130 | select_icon (GtkTreeSelection * sel, IconBrowserData * data) 131 | { 132 | GtkTreeModel *model; 133 | GtkTreeIter iter; 134 | GtkIconInfo *info; 135 | gint *sz, i; 136 | gchar *icon, *file; 137 | GString *sizes; 138 | 139 | if (!gtk_tree_selection_get_selected (sel, &model, &iter)) 140 | return; 141 | 142 | gtk_tree_model_get (model, &iter, 1, &icon, -1); 143 | 144 | gtk_image_set_from_icon_name (GTK_IMAGE (data->image), icon, GTK_ICON_SIZE_DIALOG); 145 | 146 | sz = gtk_icon_theme_get_icon_sizes (data->theme, icon); 147 | info = gtk_icon_theme_lookup_icon (data->theme, icon, sz[0], 0); 148 | 149 | if (info) 150 | file = (gchar *) gtk_icon_info_get_filename (info); 151 | else 152 | file = NULL; 153 | 154 | /* create sizes string */ 155 | i = 0; 156 | sizes = g_string_new (""); 157 | while (sz[i]) 158 | { 159 | if (sz[i] == -1) 160 | g_string_append (sizes, _("scalable ")); 161 | else 162 | g_string_append_printf (sizes, "%dx%d ", sz[i], sz[i]); 163 | i++; 164 | } 165 | /* free memory */ 166 | g_free (sz); 167 | 168 | gtk_label_set_text (GTK_LABEL (data->lname), icon); 169 | gtk_label_set_text (GTK_LABEL (data->lsize), sizes->str); 170 | gtk_label_set_text (GTK_LABEL (data->lfile), file ? file : _("built-in")); 171 | 172 | g_string_free (sizes, TRUE); 173 | 174 | if (info) 175 | g_object_unref (info); 176 | } 177 | 178 | static void 179 | select_cat (GtkTreeSelection * sel, IconBrowserData * data) 180 | { 181 | GtkTreeModel *model; 182 | GtkListStore *store; 183 | GtkTreeIter iter; 184 | gchar *cat; 185 | 186 | if (!gtk_tree_selection_get_selected (sel, &model, &iter)) 187 | return; 188 | 189 | gtk_tree_model_get (model, &iter, 0, &cat, -1); 190 | 191 | store = g_hash_table_lookup (data->icons, cat); 192 | if (!store) 193 | { 194 | store = load_icon_cat (data, cat); 195 | g_hash_table_insert (data->icons, cat, store); 196 | } 197 | gtk_tree_view_set_model (GTK_TREE_VIEW (data->icon_list), GTK_TREE_MODEL (store)); 198 | } 199 | 200 | gint 201 | main (gint argc, gchar * argv[]) 202 | { 203 | IconBrowserData *data; 204 | gchar **themes = NULL; 205 | GList *ic, *icat; 206 | GtkListStore *store; 207 | GtkTreeSelection *sel; 208 | GtkTreeViewColumn *col; 209 | GtkCellRenderer *r; 210 | GtkWidget *w, *p, *box, *t; 211 | gboolean all = FALSE, symbolic = FALSE, interactive = FALSE; 212 | 213 | GError *err = NULL; 214 | GOptionContext *ctx; 215 | 216 | GOptionEntry entrs[] = { 217 | { "all", 'a', 0, G_OPTION_ARG_NONE, &all, _("Show all icons"), NULL }, 218 | { "symbolic", 's', 0, G_OPTION_ARG_NONE, &symbolic, _("Show only symbolic icons"), NULL }, 219 | { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive, _("Select and print icon on double-click"), NULL }, 220 | { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &themes, NULL, N_("THEME") }, 221 | { NULL } 222 | }; 223 | 224 | setlocale (LC_ALL, ""); 225 | 226 | #ifdef ENABLE_NLS 227 | bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); 228 | bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 229 | textdomain (GETTEXT_PACKAGE); 230 | #endif 231 | 232 | /* Parse the command line arguments */ 233 | ctx = g_option_context_new (_("- Icon browser")); 234 | g_option_context_set_ignore_unknown_options (ctx, TRUE); 235 | g_option_context_add_main_entries (ctx, entrs, GETTEXT_PACKAGE); 236 | g_option_context_add_group (ctx, gtk_get_option_group (TRUE)); 237 | if (!g_option_context_parse (ctx, &argc, &argv, &err)) 238 | { 239 | g_printerr ("Option parsing failed: %s\n", err->message); 240 | return 1; 241 | } 242 | 243 | data = g_new0 (IconBrowserData, 1); 244 | 245 | if (all) 246 | { 247 | show_regular = TRUE; 248 | show_symbolic = TRUE; 249 | } 250 | else if (symbolic) 251 | { 252 | show_regular = FALSE; 253 | show_symbolic = TRUE; 254 | } 255 | 256 | /* load icon theme */ 257 | data->theme = gtk_icon_theme_get_default (); 258 | if (themes && themes[0]) 259 | { 260 | data->theme = gtk_icon_theme_new (); 261 | gtk_icon_theme_set_custom_theme (data->theme, themes[0]); 262 | } 263 | 264 | /* create interface */ 265 | data->win = gtk_window_new (GTK_WINDOW_TOPLEVEL); 266 | gtk_window_set_title (GTK_WINDOW (data->win), _("Icon browser")); 267 | gtk_window_set_icon_name (GTK_WINDOW (data->win), "gtk-info"); 268 | gtk_window_set_default_size (GTK_WINDOW (data->win), 500, 400); 269 | g_signal_connect (G_OBJECT (data->win), "delete-event", G_CALLBACK (gtk_main_quit), NULL); 270 | g_signal_connect (G_OBJECT (data->win), "key-press-event", G_CALLBACK (key_press_cb), NULL); 271 | 272 | box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); 273 | gtk_container_add (GTK_CONTAINER (data->win), box); 274 | gtk_container_set_border_width (GTK_CONTAINER (data->win), 5); 275 | 276 | /* create icon info box */ 277 | t = gtk_grid_new (); 278 | gtk_grid_set_row_spacing (GTK_GRID (t), 5); 279 | gtk_grid_set_column_spacing (GTK_GRID (t), 5); 280 | gtk_box_pack_start (GTK_BOX (box), t, FALSE, FALSE, 2); 281 | 282 | data->image = gtk_image_new_from_icon_name ("image-missing", GTK_ICON_SIZE_DIALOG); 283 | gtk_grid_attach (GTK_GRID (t), data->image, 0, 0, 1, 3); 284 | 285 | w = gtk_label_new (NULL); 286 | gtk_label_set_markup (GTK_LABEL (w), _("Name:")); 287 | gtk_label_set_xalign (GTK_LABEL (w), 0.0); 288 | gtk_grid_attach (GTK_GRID (t), w, 1, 0, 1, 1); 289 | 290 | data->lname = gtk_label_new (NULL); 291 | gtk_label_set_selectable (GTK_LABEL (data->lname), TRUE); 292 | gtk_label_set_xalign (GTK_LABEL (data->lname), 0.0); 293 | gtk_grid_attach (GTK_GRID (t), data->lname, 2, 0, 1, 1); 294 | gtk_widget_set_hexpand (data->lname, TRUE); 295 | 296 | w = gtk_label_new (NULL); 297 | gtk_label_set_markup (GTK_LABEL (w), _("Sizes:")); 298 | gtk_label_set_xalign (GTK_LABEL (w), 0.0); 299 | gtk_grid_attach (GTK_GRID (t), w, 1, 1, 1, 1); 300 | 301 | data->lsize = gtk_label_new (NULL); 302 | gtk_label_set_selectable (GTK_LABEL (data->lsize), TRUE); 303 | gtk_label_set_xalign (GTK_LABEL (data->lsize), 0.0); 304 | gtk_grid_attach (GTK_GRID (t), data->lsize, 2, 1, 1, 1); 305 | gtk_widget_set_hexpand (data->lsize, TRUE); 306 | 307 | w = gtk_label_new (NULL); 308 | gtk_label_set_markup (GTK_LABEL (w), _("Filename:")); 309 | gtk_label_set_xalign (GTK_LABEL (w), 0.0); 310 | gtk_grid_attach (GTK_GRID (t), w, 1, 2, 1, 1); 311 | 312 | data->lfile = gtk_label_new (NULL); 313 | gtk_label_set_selectable (GTK_LABEL (data->lfile), TRUE); 314 | gtk_label_set_xalign (GTK_LABEL (data->lfile), 0.0); 315 | gtk_grid_attach (GTK_GRID (t), data->lfile, 2, 2, 1, 1); 316 | gtk_widget_set_hexpand (data->lfile, TRUE); 317 | 318 | /* create icon browser */ 319 | p = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); 320 | gtk_paned_set_position (GTK_PANED (p), 150); 321 | gtk_box_pack_start (GTK_BOX (box), p, TRUE, TRUE, 2); 322 | 323 | /* create category list */ 324 | w = gtk_scrolled_window_new (NULL, NULL); 325 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 326 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_ETCHED_IN); 327 | gtk_paned_add1 (GTK_PANED (p), w); 328 | 329 | store = gtk_list_store_new (1, G_TYPE_STRING); 330 | 331 | data->cat_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); 332 | gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (data->cat_list), TRUE); 333 | gtk_container_add (GTK_CONTAINER (w), data->cat_list); 334 | 335 | sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->cat_list)); 336 | g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (select_cat), data); 337 | 338 | r = gtk_cell_renderer_text_new (); 339 | col = gtk_tree_view_column_new_with_attributes (_("Category"), r, "text", 0, NULL); 340 | gtk_tree_view_column_set_expand (col, TRUE); 341 | gtk_tree_view_append_column (GTK_TREE_VIEW (data->cat_list), col); 342 | 343 | /* load icons category */ 344 | data->icons = g_hash_table_new (g_direct_hash, g_direct_equal); 345 | icat = gtk_icon_theme_list_contexts (data->theme); 346 | for (ic = icat; ic; ic = ic->next) 347 | { 348 | GtkTreeIter iter; 349 | 350 | gtk_list_store_append (store, &iter); 351 | gtk_list_store_set (store, &iter, 0, ic->data, -1); 352 | g_free (ic->data); 353 | } 354 | g_list_free (icat); 355 | 356 | /* create icons list */ 357 | w = gtk_scrolled_window_new (NULL, NULL); 358 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 359 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_ETCHED_IN); 360 | gtk_paned_add2 (GTK_PANED (p), w); 361 | 362 | data->icon_list = gtk_tree_view_new (); 363 | gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (data->icon_list), TRUE); 364 | gtk_container_add (GTK_CONTAINER (w), data->icon_list); 365 | 366 | sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->icon_list)); 367 | g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (select_icon), data); 368 | 369 | if (interactive) 370 | g_signal_connect (G_OBJECT (data->icon_list), "row-activated", G_CALLBACK (print_icon), data); 371 | 372 | col = gtk_tree_view_column_new (); 373 | gtk_tree_view_column_set_title (col, _("Icons")); 374 | gtk_tree_view_column_set_sort_column_id (col, 1); 375 | r = gtk_cell_renderer_pixbuf_new (); 376 | gtk_tree_view_column_pack_start (col, r, FALSE); 377 | gtk_tree_view_column_set_attributes (col, r, "pixbuf", 0, NULL); 378 | r = gtk_cell_renderer_text_new (); 379 | gtk_tree_view_column_pack_start (col, r, FALSE); 380 | gtk_tree_view_column_set_attributes (col, r, "text", 1, NULL); 381 | gtk_tree_view_column_set_expand (col, TRUE); 382 | gtk_tree_view_append_column (GTK_TREE_VIEW (data->icon_list), col); 383 | 384 | gtk_widget_show_all (data->win); 385 | 386 | /* run it */ 387 | gtk_main (); 388 | 389 | return 0; 390 | } 391 | -------------------------------------------------------------------------------- /src/tools.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2019-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #ifdef HAVE_SPELL 26 | #include 27 | #endif 28 | 29 | #ifdef HAVE_SOURCEVIEW 30 | #include 31 | #endif 32 | 33 | #include "cpicker.h" 34 | 35 | typedef enum { 36 | PANGO_SPEC, 37 | XFT_SPEC 38 | } FontType; 39 | 40 | static gboolean set_font_type (const gchar *name, const gchar *val, gpointer d, GError **err); 41 | static gboolean set_size_type (const gchar *name, const gchar *val, gpointer d, GError **err); 42 | 43 | static FontType font_type = XFT_SPEC; 44 | 45 | static gboolean pfd_mode = FALSE; 46 | static gboolean icon_mode = FALSE; 47 | static gboolean color_mode = FALSE; 48 | static gboolean mime = FALSE; 49 | static gboolean ver = FALSE; 50 | #ifdef HAVE_SPELL 51 | static gboolean langs_mode = FALSE; 52 | #endif 53 | #ifdef HAVE_SOURCEVIEW 54 | static gboolean themes_mode = FALSE; 55 | #endif 56 | gboolean pick_color = FALSE; 57 | 58 | static guint icon_size = 24; 59 | static gchar *icon_theme_name = NULL; 60 | 61 | static gchar **args = NULL; 62 | 63 | static GOptionEntry ents[] = { 64 | { "version", 'v', 0, G_OPTION_ARG_NONE, &ver, N_("Print version"), NULL }, 65 | #ifdef HAVE_SPELL 66 | { "show-langs", 0, 0, G_OPTION_ARG_NONE, &langs_mode, N_("Show list of spell languages"), NULL }, 67 | #endif 68 | #ifdef HAVE_SOURCEVIEW 69 | { "show-themes", 0, 0, G_OPTION_ARG_NONE, &themes_mode, N_("Show list of GtkSourceView themes"), NULL }, 70 | #endif 71 | { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, NULL, N_("STRING ...") }, 72 | { NULL } 73 | }; 74 | 75 | static GOptionEntry pfd_ents[] = { 76 | { "pfd", 'f', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &pfd_mode, N_("Pango fonts description tools"), NULL }, 77 | { "xft", 'x', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, set_font_type, N_("Print font name in xft format"), NULL }, 78 | { "pango", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, set_font_type, N_("Print font name in pango format"), NULL }, 79 | { NULL } 80 | }; 81 | 82 | static GOptionEntry icon_ents[] = { 83 | { "icon", 'i', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &icon_mode, N_("Icon tools"), NULL }, 84 | { "mime", 'm', 0, G_OPTION_ARG_NONE, &mime, N_("Get icon name for mime type"), NULL }, 85 | { "size", 's', 0, G_OPTION_ARG_INT, &icon_size, N_("Use specified icon size"), N_("SIZE") }, 86 | { "type", 't', 0, G_OPTION_ARG_CALLBACK, set_size_type, N_("Get icon size from GtkIconSize type"), N_("TYPE") }, 87 | { "theme", 0, 0, G_OPTION_ARG_STRING, &icon_theme_name, N_("Use icon theme"), N_("THEME") }, 88 | { NULL } 89 | }; 90 | 91 | static GOptionEntry color_ents[] = { 92 | { "color", 'c', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &color_mode, N_("Color manipulation tools"), NULL }, 93 | { "pick", 0, 0, G_OPTION_ARG_NONE, &pick_color, N_("Pick up screen color"), NULL }, 94 | { NULL } 95 | }; 96 | 97 | static gboolean 98 | set_font_type (const gchar *name, const gchar *val, gpointer d, GError **err) 99 | { 100 | gint i = 1; 101 | 102 | if (name[i] == '-') 103 | i = 2; 104 | 105 | if (name[i] == 'p') 106 | font_type = PANGO_SPEC; 107 | else if (name[i] == 'x') 108 | font_type = XFT_SPEC; 109 | else 110 | return FALSE; 111 | 112 | return TRUE; 113 | } 114 | 115 | static gboolean 116 | set_size_type (const gchar *name, const gchar *val, gpointer d, GError **err) 117 | { 118 | gint w = 0, h = 0; 119 | 120 | if (strcasecmp (val, "MENU") == 0) 121 | gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); 122 | else if (strcasecmp (val, "BUTTON") == 0) 123 | gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); 124 | else if (strcasecmp (val, "SMALL_TOOLBAR") == 0) 125 | gtk_icon_size_lookup (GTK_ICON_SIZE_SMALL_TOOLBAR, &w, &h); 126 | else if (strcasecmp (val, "LARGE_TOOLBAR") == 0) 127 | gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &w, &h); 128 | else if (strcasecmp (val, "DND") == 0) 129 | gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &w, &h); 130 | else if (strcasecmp (val, "DIALOG") == 0) 131 | gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &w, &h); 132 | 133 | if (w && h) 134 | icon_size = MIN (w, h); 135 | 136 | return TRUE; 137 | } 138 | 139 | static gchar * 140 | parse_font (gchar *fn) 141 | { 142 | gchar **fnt; 143 | gint i = 1; 144 | GString *pfd = g_string_new (NULL); 145 | 146 | fnt = g_strsplit (fn, ":", -1); 147 | 148 | if (g_ascii_strcasecmp (fnt[0], "xft") != 0) 149 | return fnt[0]; 150 | 151 | while (fnt[i]) 152 | { 153 | if (g_ascii_strncasecmp (fnt[i], "style=", 6) == 0) 154 | g_string_append_printf (pfd, "%s ", fnt[i] + 6); 155 | else if (g_ascii_strncasecmp (fnt[i], "size=", 5) == 0) 156 | g_string_append_printf (pfd, "%s ", fnt[i] + 5); 157 | else if (g_ascii_strncasecmp (fnt[i], "pixelsize=", 10) == 0) 158 | g_string_append_printf (pfd, "%spx ", fnt[i] + 10); 159 | else 160 | g_string_append_printf (pfd, "%s ", fnt[i]); 161 | i++; 162 | } 163 | 164 | return pfd->str; 165 | } 166 | 167 | static gint 168 | run_pfd_mode () 169 | { 170 | PangoFontDescription *fnd = NULL; 171 | 172 | if (!args || !args[0]) 173 | { 174 | g_printerr (_("no font specified\n")); 175 | return 1; 176 | } 177 | 178 | /* parse font */ 179 | fnd = pango_font_description_from_string (parse_font (args[0])); 180 | if (!fnd) 181 | { 182 | g_printerr (_("cannot get font description for for string \"%s\"\n"), args[0]); 183 | return 1; 184 | } 185 | 186 | /* print font */ 187 | switch (font_type) 188 | { 189 | case PANGO_SPEC: 190 | g_print ("%s\n", pango_font_description_to_string (fnd)); 191 | break; 192 | case XFT_SPEC: 193 | { 194 | PangoFontMask mask = pango_font_description_get_set_fields (fnd); 195 | 196 | if (mask & PANGO_FONT_MASK_FAMILY) 197 | g_print ("xft:%s", pango_font_description_get_family (fnd)); 198 | else 199 | g_print ("xft:Sans"); /* simple default */ 200 | 201 | if (mask & PANGO_FONT_MASK_WEIGHT) 202 | { 203 | switch (pango_font_description_get_weight (fnd)) 204 | { 205 | case PANGO_WEIGHT_THIN: 206 | g_print (":Thin"); 207 | break; 208 | case PANGO_WEIGHT_ULTRALIGHT: 209 | g_print (":Ultralight"); 210 | break; 211 | case PANGO_WEIGHT_LIGHT: 212 | g_print (":Light"); 213 | break; 214 | case PANGO_WEIGHT_SEMILIGHT: 215 | g_print (":Semilight"); 216 | break; 217 | case PANGO_WEIGHT_BOOK: 218 | g_print (":Book"); 219 | break; 220 | case PANGO_WEIGHT_NORMAL: 221 | break; 222 | case PANGO_WEIGHT_MEDIUM: 223 | g_print (":Medium"); 224 | break; 225 | case PANGO_WEIGHT_SEMIBOLD: 226 | g_print (":Semibold"); 227 | break; 228 | case PANGO_WEIGHT_BOLD: 229 | g_print (":Bold"); 230 | break; 231 | case PANGO_WEIGHT_ULTRABOLD: 232 | g_print (":Ultrabold"); 233 | break; 234 | case PANGO_WEIGHT_HEAVY: 235 | g_print (":Heavy"); 236 | break; 237 | case PANGO_WEIGHT_ULTRAHEAVY: 238 | g_print (":Ultraheavy"); 239 | break; 240 | } 241 | } 242 | 243 | if (mask & PANGO_FONT_MASK_STYLE) 244 | { 245 | switch (pango_font_description_get_style (fnd)) 246 | { 247 | case PANGO_STYLE_NORMAL: 248 | break; 249 | case PANGO_STYLE_OBLIQUE: 250 | g_print (":Oblique"); 251 | break; 252 | case PANGO_STYLE_ITALIC: 253 | g_print (":Italic"); 254 | break; 255 | } 256 | } 257 | 258 | if (mask & PANGO_FONT_MASK_SIZE) 259 | { 260 | if (pango_font_description_get_size_is_absolute (fnd)) 261 | g_print (":pixelsize=%d", pango_font_description_get_size (fnd) / PANGO_SCALE); 262 | else 263 | g_print (":size=%d", pango_font_description_get_size (fnd) / PANGO_SCALE); 264 | } 265 | 266 | g_print ("\n"); 267 | 268 | break; 269 | } 270 | } 271 | 272 | return 0; 273 | } 274 | 275 | static gint 276 | run_icon_mode () 277 | { 278 | GtkIconTheme *theme; 279 | GtkIconInfo *ii; 280 | gchar *output = NULL; 281 | 282 | if (!args || !args[0]) 283 | { 284 | g_printerr (_("no icon specified\n")); 285 | return 1; 286 | } 287 | 288 | if (icon_theme_name) 289 | { 290 | theme = gtk_icon_theme_new (); 291 | gtk_icon_theme_set_custom_theme (theme, icon_theme_name); 292 | } 293 | else 294 | theme = gtk_icon_theme_get_default (); 295 | 296 | if (mime) 297 | { 298 | gchar *ctype = g_content_type_from_mime_type (args[0]); 299 | output = g_content_type_get_generic_icon_name (ctype); 300 | } 301 | else 302 | { 303 | ii = gtk_icon_theme_lookup_icon (theme, args[0], icon_size, 0); 304 | if (ii == NULL) 305 | return 1; 306 | output = (gchar *) gtk_icon_info_get_filename (ii); 307 | } 308 | 309 | if (output) 310 | g_print ("%s\n", output); 311 | else 312 | return 1; 313 | 314 | return 0; 315 | } 316 | 317 | static gint 318 | run_color_mode () 319 | { 320 | if (pick_color) 321 | { 322 | gtk_init (NULL, NULL); 323 | yad_get_screen_color (NULL); 324 | gtk_main (); 325 | } 326 | 327 | return 0; 328 | } 329 | 330 | #ifdef HAVE_SPELL 331 | static gint 332 | show_langs () 333 | { 334 | const GList *lng; 335 | 336 | for (lng = gspell_language_get_available (); lng; lng = lng->next) 337 | { 338 | const GspellLanguage *l = lng->data; 339 | g_print ("%s\n", gspell_language_get_code (l)); 340 | } 341 | 342 | return 0; 343 | } 344 | #endif 345 | 346 | #ifdef HAVE_SOURCEVIEW 347 | static gint 348 | show_themes () 349 | { 350 | GtkSourceStyleSchemeManager *sm; 351 | const gchar **si; 352 | guint i = 0; 353 | 354 | sm = gtk_source_style_scheme_manager_get_default (); 355 | if ((si = (const gchar **) gtk_source_style_scheme_manager_get_scheme_ids (sm)) == NULL) 356 | return 1; 357 | 358 | while (si[i]) 359 | { 360 | GtkSourceStyleScheme *s = gtk_source_style_scheme_manager_get_scheme (sm, si[i]); 361 | g_print ("%s\n", gtk_source_style_scheme_get_name (s)); 362 | i++; 363 | } 364 | 365 | return 0; 366 | } 367 | #endif 368 | 369 | int 370 | main (int argc, char *argv[]) 371 | { 372 | GOptionContext *ctx; 373 | GOptionGroup *grp; 374 | GError *err = NULL; 375 | gint ret = 0; 376 | 377 | setlocale (LC_ALL, ""); 378 | 379 | #ifdef ENABLE_NLS 380 | bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); 381 | bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 382 | textdomain (GETTEXT_PACKAGE); 383 | #endif 384 | 385 | gtk_init (&argc, &argv); 386 | 387 | ctx = g_option_context_new (_("- yad miscellaneous tools")); 388 | g_option_context_add_main_entries (ctx, ents, GETTEXT_PACKAGE); 389 | 390 | grp = g_option_group_new ("pfd", _("PFD mode"), _("Show pfd mode options"), NULL, NULL); 391 | g_option_group_add_entries (grp, pfd_ents); 392 | g_option_group_set_translation_domain (grp, GETTEXT_PACKAGE); 393 | g_option_context_add_group (ctx, grp); 394 | 395 | grp = g_option_group_new ("icon", _("Icon mode"), _("Show icon mode options"), NULL, NULL); 396 | g_option_group_add_entries (grp, icon_ents); 397 | g_option_group_set_translation_domain (grp, GETTEXT_PACKAGE); 398 | g_option_context_add_group (ctx, grp); 399 | 400 | grp = g_option_group_new ("color", _("Color mode"), _("Show color mode options"), NULL, NULL); 401 | g_option_group_add_entries (grp, color_ents); 402 | g_option_group_set_translation_domain (grp, GETTEXT_PACKAGE); 403 | g_option_context_add_group (ctx, grp); 404 | 405 | if (!g_option_context_parse (ctx, &argc, &argv, &err)) 406 | { 407 | g_printerr (_("option parsing failed: %s\n"), err->message); 408 | return 1; 409 | } 410 | 411 | if (ver) 412 | { 413 | g_print ("%s\n", VERSION); 414 | return 0; 415 | } 416 | 417 | if (pfd_mode) 418 | ret = run_pfd_mode (); 419 | else if (icon_mode) 420 | ret = run_icon_mode (); 421 | else if (color_mode) 422 | ret = run_color_mode (); 423 | #ifdef HAVE_SPELL 424 | else if (langs_mode) 425 | ret = show_langs (); 426 | #endif 427 | #ifdef HAVE_SOURCEVIEW 428 | else if (themes_mode) 429 | ret = show_themes (); 430 | #endif 431 | else 432 | { 433 | g_printerr (_("no mode specified\n")); 434 | return 1; 435 | } 436 | 437 | return ret; 438 | } 439 | -------------------------------------------------------------------------------- /src/notification.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "yad.h" 27 | 28 | typedef struct { 29 | gchar *name; 30 | gchar *action; 31 | gchar *icon; 32 | } MenuData; 33 | 34 | static GtkStatusIcon *status_icon; 35 | 36 | static gchar *icon = NULL; 37 | static gchar *action = NULL; 38 | 39 | static GSList *menu_data = NULL; 40 | 41 | static gint exit_code; 42 | 43 | static void popup_menu_cb (GtkStatusIcon *, guint, guint, gpointer); 44 | 45 | static void 46 | free_menu_data (gpointer data) 47 | { 48 | MenuData *m = (MenuData *) data; 49 | 50 | if (m) { 51 | g_free (m->name); 52 | g_free (m->action); 53 | g_free (m->icon); 54 | g_free (m); 55 | } 56 | } 57 | 58 | static void 59 | parse_menu_str (gchar * str) 60 | { 61 | gchar **menu_vals; 62 | gint i = 0; 63 | 64 | if (menu_data) 65 | { 66 | g_slist_free_full (menu_data, free_menu_data); 67 | menu_data = NULL; 68 | } 69 | 70 | menu_vals = g_strsplit (str, options.common_data.separator, -1); 71 | 72 | while (menu_vals[i] != NULL) 73 | { 74 | MenuData *mdata = g_new0 (MenuData, 1); 75 | gchar **s = g_strsplit (menu_vals[i], options.common_data.item_separator, 3); 76 | 77 | if (s[0]) 78 | { 79 | YadStock sit; 80 | if (stock_lookup (s[0], &sit)) 81 | { 82 | mdata->name = g_strdup (sit.label); 83 | mdata->icon = g_strdup (sit.icon); 84 | } 85 | else 86 | mdata->name = g_strdup (s[0]); 87 | if (s[1]) 88 | { 89 | mdata->action = g_strdup (s[1]); 90 | if (s[2]) 91 | mdata->icon = g_strdup (s[2]); 92 | } 93 | } 94 | menu_data = g_slist_append (menu_data, mdata); 95 | g_strfreev (s); 96 | i++; 97 | } 98 | 99 | g_strfreev (menu_vals); 100 | } 101 | 102 | static void 103 | timeout_cb (gpointer data) 104 | { 105 | exit_code = YAD_RESPONSE_TIMEOUT; 106 | gtk_main_quit (); 107 | } 108 | 109 | static void 110 | set_icon (void) 111 | { 112 | GdkPixbuf *pixbuf; 113 | GError *err = NULL; 114 | 115 | if (icon == NULL) 116 | { 117 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 118 | gtk_status_icon_set_from_icon_name (status_icon, "yad"); 119 | G_GNUC_END_IGNORE_DEPRECATIONS; 120 | return; 121 | } 122 | 123 | if (g_file_test (icon, G_FILE_TEST_EXISTS)) 124 | { 125 | gint isize = (options.common_data.icon_size > 0) ? options.common_data.icon_size : 16; 126 | 127 | pixbuf = gdk_pixbuf_new_from_file_at_scale (icon, isize, isize, TRUE, &err); 128 | if (err) 129 | { 130 | g_printerr (_("Could not load notification icon '%s': %s\n"), icon, err->message); 131 | g_clear_error (&err); 132 | } 133 | if (pixbuf) 134 | { 135 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 136 | gtk_status_icon_set_from_pixbuf (status_icon, pixbuf); 137 | G_GNUC_END_IGNORE_DEPRECATIONS; 138 | g_object_unref (pixbuf); 139 | } 140 | else 141 | { 142 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 143 | gtk_status_icon_set_from_icon_name (status_icon, "yad"); 144 | G_GNUC_END_IGNORE_DEPRECATIONS; 145 | } 146 | } 147 | else 148 | { 149 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 150 | gtk_status_icon_set_from_icon_name (status_icon, icon); 151 | G_GNUC_END_IGNORE_DEPRECATIONS; 152 | } 153 | } 154 | 155 | static gboolean 156 | activate_cb (GtkWidget * widget, YadData * data) 157 | { 158 | if ((action == NULL && !options.common_data.listen) || (action && g_ascii_strcasecmp (action, "quit") == 0)) 159 | { 160 | exit_code = YAD_RESPONSE_OK; 161 | gtk_main_quit (); 162 | } 163 | else if (action) 164 | { 165 | if (g_ascii_strcasecmp (action, "menu") == 0) 166 | popup_menu_cb (GTK_STATUS_ICON (widget), 1, GDK_CURRENT_TIME, data); 167 | else 168 | run_command_async (action); 169 | } 170 | 171 | return TRUE; 172 | } 173 | 174 | static gboolean 175 | middle_quit_cb (GtkStatusIcon * icon, GdkEventButton * ev, gpointer data) 176 | { 177 | if (ev->button == 2) 178 | { 179 | if (options.data.escape_ok) 180 | exit_code = YAD_RESPONSE_OK; 181 | else 182 | exit_code = YAD_RESPONSE_ESC; 183 | gtk_main_quit (); 184 | } 185 | 186 | return FALSE; 187 | } 188 | 189 | static void 190 | popup_menu_item_activate_cb (GtkWidget * w, gpointer data) 191 | { 192 | gchar *cmd = (gchar *) data; 193 | 194 | if (cmd) 195 | { 196 | if (g_ascii_strcasecmp (g_strstrip (cmd), "quit") == 0) 197 | { 198 | exit_code = YAD_RESPONSE_OK; 199 | gtk_main_quit (); 200 | } 201 | else 202 | run_command_async (cmd); 203 | } 204 | } 205 | 206 | static void 207 | popup_menu_cb (GtkStatusIcon *icon, guint button, guint activate_time, gpointer data) 208 | { 209 | GtkWidget *menu; 210 | GtkWidget *item; 211 | GSList *m; 212 | 213 | if (!menu_data) 214 | return; 215 | 216 | menu = gtk_menu_new (); 217 | gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE); 218 | 219 | for (m = menu_data; m; m = m->next) 220 | { 221 | MenuData *d = (MenuData *) m->data; 222 | 223 | if (d->name) 224 | { 225 | GtkWidget *b, *i, *l; 226 | 227 | item = gtk_menu_item_new (); 228 | b = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); 229 | 230 | if (d->icon) 231 | { 232 | GdkPixbuf *pb = get_pixbuf (d->icon, YAD_SMALL_ICON, TRUE); 233 | if (pb) 234 | { 235 | i = gtk_image_new_from_pixbuf (pb); 236 | gtk_container_add (GTK_CONTAINER (b), i); 237 | g_object_unref (pb); 238 | } 239 | } 240 | l = gtk_label_new_with_mnemonic (d->name); 241 | gtk_label_set_xalign (GTK_LABEL (l), 0.0); 242 | gtk_label_set_mnemonic_widget (GTK_LABEL (l), item); 243 | gtk_box_pack_end (GTK_BOX (b), l, TRUE, TRUE, 0); 244 | 245 | gtk_container_add (GTK_CONTAINER (item), b); 246 | 247 | g_signal_connect (GTK_MENU_ITEM (item), "activate", 248 | G_CALLBACK (popup_menu_item_activate_cb), (gpointer) d->action); 249 | } 250 | else 251 | item = gtk_separator_menu_item_new (); 252 | 253 | gtk_widget_show_all (item); 254 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); 255 | } 256 | 257 | gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL); 258 | } 259 | 260 | static gboolean 261 | handle_stdin (GIOChannel * channel, GIOCondition condition, gpointer data) 262 | { 263 | if ((condition & G_IO_IN) != 0) 264 | { 265 | GString *string; 266 | GError *err = NULL; 267 | 268 | string = g_string_new (NULL); 269 | while (channel->is_readable == FALSE) 270 | usleep (100); 271 | 272 | do 273 | { 274 | gint status; 275 | gchar *command = NULL, *value = NULL, **args; 276 | 277 | do 278 | { 279 | status = g_io_channel_read_line_string (channel, string, NULL, &err); 280 | 281 | while (gdk_events_pending ()) 282 | gtk_main_iteration (); 283 | } 284 | while (status == G_IO_STATUS_AGAIN); 285 | 286 | if (status != G_IO_STATUS_NORMAL) 287 | { 288 | if (err) 289 | { 290 | g_printerr ("yad_notification_handle_stdin(): %s\n", err->message); 291 | g_error_free (err); 292 | err = NULL; 293 | } 294 | /* stop handling but not exit */ 295 | g_io_channel_shutdown (channel, TRUE, NULL); 296 | return FALSE; 297 | } 298 | 299 | strip_new_line (string->str); 300 | if (!string->str[0]) 301 | continue; 302 | 303 | args = g_strsplit (string->str, ":", 2); 304 | command = g_strdup (args[0]); 305 | if (args[1]) 306 | value = g_strdup (args[1]); 307 | g_strfreev (args); 308 | if (value) 309 | g_strstrip (value); 310 | 311 | if (!g_ascii_strcasecmp (command, "icon") && value) 312 | { 313 | g_free (icon); 314 | icon = g_strdup (value); 315 | 316 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 317 | if (gtk_status_icon_get_visible (status_icon) && gtk_status_icon_is_embedded (status_icon)) 318 | set_icon (); 319 | G_GNUC_END_IGNORE_DEPRECATIONS; 320 | } 321 | else if (!g_ascii_strcasecmp (command, "tooltip")) 322 | { 323 | if (g_utf8_validate (value, -1, NULL)) 324 | { 325 | gchar *message = g_strcompress (value); 326 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 327 | if (!options.data.no_markup) 328 | gtk_status_icon_set_tooltip_markup (status_icon, message); 329 | else 330 | gtk_status_icon_set_tooltip_text (status_icon, message); 331 | G_GNUC_END_IGNORE_DEPRECATIONS; 332 | g_free (message); 333 | } 334 | else 335 | g_printerr (_("Invalid UTF-8 in tooltip!\n")); 336 | } 337 | else if (!g_ascii_strcasecmp (command, "visible")) 338 | { 339 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 340 | if (!g_ascii_strcasecmp (value, "false")) 341 | gtk_status_icon_set_visible (status_icon, FALSE); 342 | else 343 | gtk_status_icon_set_visible (status_icon, TRUE); 344 | G_GNUC_END_IGNORE_DEPRECATIONS; 345 | } 346 | else if (!g_ascii_strcasecmp (command, "action")) 347 | { 348 | g_free (action); 349 | action = NULL; 350 | if (value && *value) 351 | action = g_strdup (value); 352 | } 353 | else if (!g_ascii_strcasecmp (command, "quit")) 354 | { 355 | exit_code = YAD_RESPONSE_OK; 356 | gtk_main_quit (); 357 | } 358 | else if (!g_ascii_strcasecmp (command, "menu")) 359 | { 360 | if (value && *value) 361 | parse_menu_str (value); 362 | } 363 | else 364 | g_printerr (_("Unknown command '%s'\n"), command); 365 | 366 | g_free (command); 367 | g_free (value); 368 | } 369 | while (g_io_channel_get_buffer_condition (channel) == G_IO_IN); 370 | g_string_free (string, TRUE); 371 | } 372 | 373 | if ((condition & G_IO_HUP) != 0) 374 | { 375 | g_io_channel_shutdown (channel, TRUE, NULL); 376 | gtk_main_quit (); 377 | return FALSE; 378 | } 379 | 380 | return TRUE; 381 | } 382 | 383 | gint 384 | yad_notification_run () 385 | { 386 | GIOChannel *channel = NULL; 387 | 388 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 389 | status_icon = gtk_status_icon_new (); 390 | G_GNUC_END_IGNORE_DEPRECATIONS; 391 | 392 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 393 | if (options.data.dialog_text) 394 | { 395 | if (!options.data.no_markup) 396 | gtk_status_icon_set_tooltip_markup (status_icon, options.data.dialog_text); 397 | else 398 | gtk_status_icon_set_tooltip_text (status_icon, options.data.dialog_text); 399 | } 400 | else 401 | gtk_status_icon_set_tooltip_text (status_icon, _("Yad notification")); 402 | G_GNUC_END_IGNORE_DEPRECATIONS; 403 | 404 | if (options.data.dialog_image) 405 | icon = g_strdup (options.data.dialog_image); 406 | if (options.common_data.command) 407 | action = g_strdup (options.common_data.command); 408 | 409 | set_icon (); 410 | 411 | g_signal_connect (status_icon, "activate", G_CALLBACK (activate_cb), NULL); 412 | g_signal_connect (status_icon, "popup_menu", G_CALLBACK (popup_menu_cb), NULL); 413 | 414 | if (options.notification_data.menu) 415 | parse_menu_str (options.notification_data.menu); 416 | 417 | /* quit on middle click (like press Esc) */ 418 | if (options.notification_data.middle) 419 | g_signal_connect (status_icon, "button-press-event", G_CALLBACK (middle_quit_cb), NULL); 420 | 421 | if (options.common_data.listen) 422 | { 423 | channel = g_io_channel_unix_new (0); 424 | if (channel) 425 | { 426 | g_io_channel_set_encoding (channel, NULL, NULL); 427 | g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); 428 | g_io_add_watch (channel, G_IO_IN | G_IO_HUP, handle_stdin, NULL); 429 | } 430 | } 431 | 432 | /* Show icon and wait */ 433 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 434 | gtk_status_icon_set_visible (status_icon, !options.notification_data.hidden); 435 | G_GNUC_END_IGNORE_DEPRECATIONS; 436 | 437 | if (options.data.timeout > 0) 438 | g_timeout_add_seconds (options.data.timeout, (GSourceFunc) timeout_cb, NULL); 439 | 440 | gtk_main (); 441 | 442 | return exit_code; 443 | } 444 | -------------------------------------------------------------------------------- /src/progress.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "yad.h" 28 | 29 | static GSList *progress_bars = NULL; 30 | static guint nbars = 0; 31 | 32 | static GtkWidget *progress_log; 33 | static GtkTextBuffer *log_buffer; 34 | 35 | static gboolean single_mode = FALSE; 36 | 37 | static gboolean 38 | pulsate_progress_bar (GtkProgressBar *bar) 39 | { 40 | gtk_progress_bar_pulse (bar); 41 | return G_SOURCE_CONTINUE; 42 | } 43 | 44 | static gboolean 45 | handle_stdin (GIOChannel *channel, GIOCondition condition, gpointer data) 46 | { 47 | float percentage = 0.0; 48 | 49 | if ((condition == G_IO_IN) || (condition == G_IO_IN + G_IO_HUP)) 50 | { 51 | GString *string; 52 | gchar **value; 53 | GError *err = NULL; 54 | 55 | string = g_string_new (NULL); 56 | 57 | while (channel->is_readable != TRUE) 58 | usleep (100); 59 | 60 | do 61 | { 62 | gint status, num; 63 | GtkProgressBar *pb; 64 | YadProgressBar *b; 65 | 66 | do 67 | { 68 | status = g_io_channel_read_line_string (channel, string, NULL, &err); 69 | 70 | while (gtk_events_pending ()) 71 | gtk_main_iteration (); 72 | } 73 | while (status == G_IO_STATUS_AGAIN); 74 | 75 | if (status != G_IO_STATUS_NORMAL) 76 | { 77 | if (err) 78 | { 79 | g_printerr ("yad_multi_progress_handle_stdin(): %s\n", err->message); 80 | g_error_free (err); 81 | err = NULL; 82 | } 83 | /* stop handling */ 84 | g_io_channel_shutdown (channel, TRUE, NULL); 85 | return FALSE; 86 | } 87 | 88 | if (single_mode) 89 | { 90 | value = g_new0 (gchar *, 2); 91 | value[1] = g_strdup (string->str); 92 | num = 0; 93 | } 94 | else 95 | { 96 | value = g_strsplit (string->str, ":", 2); 97 | num = atoi (value[0]) - 1; 98 | if (num < 0 || num > nbars - 1) 99 | continue; 100 | } 101 | 102 | pb = GTK_PROGRESS_BAR (g_slist_nth_data (progress_bars, num)); 103 | b = (YadProgressBar *) g_slist_nth_data (options.progress_data.bars, num); 104 | 105 | if (value[1] && value[1][0] == '#') 106 | { 107 | gchar *match; 108 | 109 | /* We have a comment, so let's try to change the label */ 110 | match = g_strcompress (value[1] + 1); 111 | strip_new_line (match); 112 | if (options.progress_data.log) 113 | { 114 | gchar *logline; 115 | GtkTextIter end; 116 | 117 | logline = g_strdup_printf ("%s\n", match); /* add new line */ 118 | gtk_text_buffer_get_end_iter (log_buffer, &end); 119 | if (options.data.no_markup) 120 | gtk_text_buffer_insert (log_buffer, &end, logline, -1); 121 | else 122 | gtk_text_buffer_insert_markup (log_buffer, &end, logline, -1); 123 | g_free (logline); 124 | 125 | /* scroll to end */ 126 | while (gtk_events_pending ()) 127 | gtk_main_iteration (); 128 | gtk_text_buffer_get_end_iter (log_buffer, &end); 129 | gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (progress_log), &end, 0, FALSE, 0, 0); 130 | } 131 | else 132 | { 133 | if (!options.common_data.hide_text) 134 | gtk_progress_bar_set_text (pb, match); 135 | } 136 | g_free (match); 137 | } 138 | else 139 | { 140 | if (value[1] && b->type == YAD_PROGRESS_PULSE) 141 | gtk_progress_bar_pulse (pb); 142 | else if (value[1] && b->type == YAD_PROGRESS_CPULSE) 143 | continue; /* just skip */ 144 | else if (value[1] && b->type == YAD_PROGRESS_PERM) 145 | { 146 | guint id; 147 | 148 | if (strncmp (value[1], "start", 5) == 0) 149 | { 150 | id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pb), "id")); 151 | if (id == 0) 152 | { 153 | id = g_timeout_add (100, (GSourceFunc) pulsate_progress_bar, pb); 154 | g_object_set_data (G_OBJECT (pb), "id", GINT_TO_POINTER (id)); 155 | } 156 | } 157 | else if (strncmp (value[1], "stop", 4) == 0) 158 | { 159 | id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pb), "id")); 160 | if (id > 0) 161 | { 162 | g_source_remove (id); 163 | g_object_set_data (G_OBJECT (pb), "id", GINT_TO_POINTER (0)); 164 | } 165 | } 166 | } 167 | else 168 | { 169 | if (!value[1] || !g_ascii_isdigit (*value[1])) 170 | continue; 171 | 172 | /* Now try to convert the thing to a number */ 173 | percentage = atoi (value[1]); 174 | if (percentage >= 100) 175 | gtk_progress_bar_set_fraction (pb, 1.0); 176 | else 177 | gtk_progress_bar_set_fraction (pb, percentage / 100.0); 178 | 179 | /* Check if all of progress bars reaches 100% */ 180 | if (options.progress_data.autoclose && options.plug == -1) 181 | { 182 | guint i; 183 | gboolean close = TRUE; 184 | gboolean need_close = FALSE; 185 | 186 | if (options.progress_data.watch_bar > 0 && options.progress_data.watch_bar <= nbars) 187 | { 188 | GtkProgressBar *cpb = GTK_PROGRESS_BAR (g_slist_nth_data (progress_bars, 189 | options.progress_data.watch_bar - 1)); 190 | 191 | need_close = TRUE; 192 | if (gtk_progress_bar_get_fraction (cpb) != 1.0) 193 | close = FALSE; 194 | } 195 | else 196 | { 197 | for (i = 0; i < nbars; i++) 198 | { 199 | GtkProgressBar *cpb = GTK_PROGRESS_BAR (g_slist_nth_data (progress_bars, i)); 200 | YadProgressBar *cb = (YadProgressBar *) g_slist_nth_data (options.progress_data.bars, i); 201 | 202 | if (cb->type != YAD_PROGRESS_PULSE) 203 | { 204 | need_close = TRUE; 205 | if (gtk_progress_bar_get_fraction (cpb) != 1.0) 206 | { 207 | close = FALSE; 208 | break; 209 | } 210 | } 211 | } 212 | } 213 | 214 | if (need_close && close) 215 | yad_exit (options.data.def_resp); 216 | } 217 | } 218 | } 219 | } 220 | while (g_io_channel_get_buffer_condition (channel) == G_IO_IN); 221 | g_string_free (string, TRUE); 222 | } 223 | 224 | if ((condition != G_IO_IN) && (condition != G_IO_IN + G_IO_HUP)) 225 | { 226 | g_io_channel_shutdown (channel, TRUE, NULL); 227 | 228 | if (options.progress_data.autoclose && options.plug == -1) 229 | yad_exit (options.data.def_resp); 230 | 231 | return FALSE; 232 | } 233 | return TRUE; 234 | } 235 | 236 | GtkWidget * 237 | progress_create_widget (GtkWidget *dlg) 238 | { 239 | GtkWidget *table, *w = NULL; 240 | GIOChannel *channel; 241 | GSList *b; 242 | gint i = 0; 243 | 244 | nbars = g_slist_length (options.progress_data.bars); 245 | if (nbars < 1) 246 | { 247 | YadProgressBar *bar = g_new0 (YadProgressBar, 1); 248 | 249 | if (options.debug) 250 | g_printerr (_("WARNING: You are using old-style progress dialog. This features is obsolete now, please use --bar style instead\n")); 251 | 252 | if (options.progress_data.pulsate) 253 | bar->type = YAD_PROGRESS_PULSE; 254 | else if (options.progress_data.rtl) 255 | bar->type = YAD_PROGRESS_RTL; 256 | else 257 | bar->type = YAD_PROGRESS_NORMAL; 258 | 259 | /* special case */ 260 | if (options.progress_data.cont) 261 | bar->type = YAD_PROGRESS_CPULSE; 262 | 263 | if (options.progress_data.progress_text) 264 | bar->name = options.progress_data.progress_text; 265 | 266 | options.progress_data.bars = g_slist_append (options.progress_data.bars, bar); 267 | nbars = 1; 268 | 269 | options.progress_data.watch_bar = 1; 270 | 271 | single_mode = TRUE; 272 | } 273 | 274 | table = gtk_grid_new (); 275 | gtk_grid_set_row_spacing (GTK_GRID (table), 2); 276 | gtk_grid_set_column_spacing (GTK_GRID (table), 2); 277 | 278 | if (options.common_data.scroll) 279 | { 280 | GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL); 281 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE); 282 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.data.hscroll_policy, options.data.vscroll_policy); 283 | gtk_container_add (GTK_CONTAINER (sw), table); 284 | w = sw; 285 | } 286 | else 287 | w = table; 288 | 289 | for (b = options.progress_data.bars; b; b = b->next) 290 | { 291 | GtkWidget *l, *w; 292 | YadProgressBar *p = (YadProgressBar *) b->data; 293 | 294 | /* add label */ 295 | l = gtk_label_new (NULL); 296 | if (options.data.no_markup) 297 | gtk_label_set_text (GTK_LABEL (l), p->name); 298 | else 299 | gtk_label_set_markup (GTK_LABEL (l), p->name); 300 | gtk_label_set_xalign (GTK_LABEL (l), options.common_data.align); 301 | 302 | if (options.common_data.vertical) 303 | gtk_grid_attach (GTK_GRID (table), l, i, 1, 1, 1); 304 | else 305 | gtk_grid_attach (GTK_GRID (table), l, 0, i, 1, 1); 306 | 307 | /* add progress bar */ 308 | w = gtk_progress_bar_new (); 309 | gtk_widget_set_name (w, "yad-progress-widget"); 310 | gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (w), !options.common_data.hide_text); 311 | 312 | if (p->type != YAD_PROGRESS_PULSE || p->type != YAD_PROGRESS_CPULSE) 313 | { 314 | if (options.extra_data && options.extra_data[i]) 315 | { 316 | if (g_ascii_isdigit (*options.extra_data[i])) 317 | gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w), atoi (options.extra_data[i]) / 100.0); 318 | } 319 | } 320 | else 321 | { 322 | if (options.extra_data && options.extra_data[i]) 323 | { 324 | if (g_ascii_isdigit (*options.extra_data[i])) 325 | gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (w), atoi (options.extra_data[i]) / 100.0); 326 | } 327 | } 328 | 329 | gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (w), p->type == YAD_PROGRESS_RTL); 330 | 331 | if (options.common_data.vertical) 332 | { 333 | gtk_orientable_set_orientation (GTK_ORIENTABLE (w), GTK_ORIENTATION_VERTICAL); 334 | gtk_grid_attach (GTK_GRID (table), w, i, 0, 1, 1); 335 | gtk_widget_set_vexpand (w, TRUE); 336 | } 337 | else 338 | { 339 | gtk_grid_attach (GTK_GRID (table), w, 1, i, 1, 1); 340 | gtk_widget_set_hexpand (w, TRUE); 341 | } 342 | 343 | progress_bars = g_slist_append (progress_bars, w); 344 | 345 | if (p->type == YAD_PROGRESS_CPULSE) 346 | g_timeout_add_seconds (1, (GSourceFunc) pulsate_progress_bar, w); 347 | 348 | i++; 349 | } 350 | 351 | if (options.progress_data.log) 352 | { 353 | GtkWidget *ex, *sw; 354 | 355 | ex = gtk_expander_new (options.progress_data.log); 356 | gtk_expander_set_spacing (GTK_EXPANDER (ex), 2); 357 | gtk_expander_set_expanded (GTK_EXPANDER (ex), options.progress_data.log_expanded); 358 | 359 | if (options.common_data.vertical) 360 | gtk_grid_attach (GTK_GRID (table), ex, 0, 2, i, 1); 361 | else 362 | gtk_grid_attach (GTK_GRID (table), ex, 0, i, 2, 1); 363 | 364 | sw = gtk_scrolled_window_new (NULL, NULL); 365 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); 366 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.data.hscroll_policy, options.data.vscroll_policy); 367 | gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE); 368 | gtk_container_add (GTK_CONTAINER (ex), sw); 369 | 370 | progress_log = gtk_text_view_new (); 371 | gtk_widget_set_name (progress_log, "yad-text-widget"); 372 | gtk_widget_set_size_request (progress_log, -1, options.progress_data.log_height); 373 | gtk_container_add (GTK_CONTAINER (sw), progress_log); 374 | 375 | log_buffer = gtk_text_buffer_new (NULL); 376 | gtk_text_view_set_buffer (GTK_TEXT_VIEW (progress_log), log_buffer); 377 | gtk_text_view_set_left_margin (GTK_TEXT_VIEW (progress_log), 5); 378 | gtk_text_view_set_right_margin (GTK_TEXT_VIEW (progress_log), 5); 379 | gtk_text_view_set_editable (GTK_TEXT_VIEW (progress_log), FALSE); 380 | gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (progress_log), FALSE); 381 | } 382 | 383 | channel = g_io_channel_unix_new (0); 384 | g_io_channel_set_encoding (channel, NULL, NULL); 385 | g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); 386 | g_io_add_watch (channel, G_IO_IN | G_IO_HUP, handle_stdin, dlg); 387 | 388 | return w; 389 | } 390 | -------------------------------------------------------------------------------- /src/print.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of YAD. 3 | * 4 | * YAD is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * YAD is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with YAD. If not, see . 16 | * 17 | * Copyright (C) 2008-2025, Victor Ananjevsky 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "yad.h" 26 | 27 | #define HEADER_HEIGHT (10*72/25.4) 28 | #define HEADER_GAP (3*72/25.4) 29 | #define HEADER_FONT "Sans 11" 30 | 31 | #define FONTNAME "Monospace" 32 | #define FONTSIZE 11.0 33 | 34 | static gchar **text; 35 | static gint nlines, npages; 36 | 37 | static PangoFontDescription *fdesc = NULL; 38 | 39 | static void 40 | draw_header (GtkPrintContext * cnt, gint pn, gint pc) 41 | { 42 | cairo_t *cr; 43 | PangoFontDescription *desc; 44 | PangoLayout *layout; 45 | gint pw, tw, th; 46 | gchar *page; 47 | 48 | cr = gtk_print_context_get_cairo_context (cnt); 49 | pw = gtk_print_context_get_width (cnt); 50 | 51 | layout = gtk_print_context_create_pango_layout (cnt); 52 | 53 | desc = pango_font_description_from_string (HEADER_FONT); 54 | pango_layout_set_font_description (layout, desc); 55 | pango_font_description_free (desc); 56 | 57 | pango_layout_set_text (layout, options.common_data.uri, -1); 58 | pango_layout_get_pixel_size (layout, &tw, &th); 59 | if (tw > pw) 60 | { 61 | pango_layout_set_width (layout, pw); 62 | pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_START); 63 | pango_layout_get_pixel_size (layout, &tw, &th); 64 | } 65 | 66 | cairo_move_to (cr, (pw - tw) / 2, (HEADER_HEIGHT - th) / 2); 67 | pango_cairo_show_layout (cr, layout); 68 | 69 | page = g_strdup_printf ("%d/%d", pn, pc); 70 | pango_layout_set_text (layout, page, -1); 71 | g_free (page); 72 | 73 | pango_layout_set_width (layout, -1); 74 | pango_layout_get_pixel_size (layout, &tw, &th); 75 | cairo_move_to (cr, pw - tw - 4, (HEADER_HEIGHT - th) / 2); 76 | pango_cairo_show_layout (cr, layout); 77 | 78 | g_object_unref (layout); 79 | 80 | cairo_move_to (cr, 0.0, HEADER_HEIGHT); 81 | cairo_line_to (cr, pw, HEADER_HEIGHT); 82 | 83 | cairo_set_source_rgb (cr, 0, 0, 0); 84 | cairo_set_line_width (cr, 1); 85 | cairo_stroke (cr); 86 | } 87 | 88 | static void 89 | begin_print_text (GtkPrintOperation * op, GtkPrintContext * cnt, gpointer data) 90 | { 91 | gchar *buf; 92 | gint i = 0; 93 | gdouble ph; 94 | 95 | /* load file */ 96 | g_file_get_contents (options.common_data.uri, &buf, NULL, NULL); 97 | text = g_strsplit (buf, "\n", 0); 98 | g_free (buf); 99 | 100 | while (text[i] != NULL) 101 | i++; 102 | 103 | ph = gtk_print_context_get_height (cnt); 104 | if (options.print_data.headers) 105 | ph -= HEADER_HEIGHT + HEADER_GAP; 106 | 107 | nlines = ph / FONTSIZE; 108 | npages = i / nlines + 1; 109 | gtk_print_operation_set_n_pages (op, npages); 110 | 111 | /* set font */ 112 | if (options.common_data.font) 113 | fdesc = pango_font_description_from_string (options.common_data.font); 114 | else 115 | { 116 | fdesc = pango_font_description_from_string (FONTNAME); 117 | pango_font_description_set_size (fdesc, FONTSIZE * PANGO_SCALE); 118 | } 119 | } 120 | 121 | static void 122 | draw_page_text (GtkPrintOperation * op, GtkPrintContext * cnt, gint page, gpointer data) 123 | { 124 | cairo_t *cr; 125 | PangoLayout *layout; 126 | gint i, line; 127 | 128 | cr = gtk_print_context_get_cairo_context (cnt); 129 | 130 | /* create header */ 131 | if (options.print_data.headers) 132 | draw_header (cnt, page + 1, npages); 133 | 134 | /* add text */ 135 | layout = gtk_print_context_create_pango_layout (cnt); 136 | pango_layout_set_font_description (layout, fdesc); 137 | 138 | cairo_move_to (cr, 0, HEADER_HEIGHT + HEADER_GAP); 139 | 140 | line = page * nlines; 141 | for (i = 0; i < nlines; i++) 142 | { 143 | if (text[line + i] == NULL) 144 | break; 145 | pango_layout_set_text (layout, text[line + i], -1); 146 | pango_cairo_show_layout (cr, layout); 147 | cairo_rel_move_to (cr, 0, FONTSIZE); 148 | } 149 | 150 | g_object_unref (layout); 151 | } 152 | 153 | static void 154 | draw_page_image (GtkPrintOperation * op, GtkPrintContext * cnt, gint page, gpointer data) 155 | { 156 | cairo_t *cr; 157 | GdkPixbuf *pb, *spb; 158 | guint iw, ih; 159 | gdouble pw, ph; 160 | gdouble factor; 161 | 162 | cr = gtk_print_context_get_cairo_context (cnt); 163 | 164 | pw = gtk_print_context_get_width (cnt); 165 | ph = gtk_print_context_get_height (cnt); 166 | 167 | /* create header */ 168 | if (options.print_data.headers) 169 | { 170 | ph -= HEADER_HEIGHT + HEADER_GAP; 171 | draw_header (cnt, 1, 1); 172 | } 173 | 174 | /* scale image to page size */ 175 | pb = gdk_pixbuf_new_from_file (options.common_data.uri, NULL); 176 | iw = gdk_pixbuf_get_width (pb); 177 | ih = gdk_pixbuf_get_height (pb); 178 | 179 | if (pw < iw || ph < ih) 180 | { 181 | factor = MIN (pw / iw, ph / ih); 182 | factor = (factor > 1.0) ? 1.0 : factor; 183 | spb = gdk_pixbuf_scale_simple (pb, iw * factor, ih * factor, GDK_INTERP_HYPER); 184 | } 185 | else 186 | spb = g_object_ref (pb); 187 | g_object_unref (pb); 188 | 189 | /* add image to surface */ 190 | gdk_cairo_set_source_pixbuf (cr, spb, 0.0, HEADER_HEIGHT + HEADER_GAP); 191 | cairo_paint (cr); 192 | g_object_unref (spb); 193 | } 194 | 195 | static void 196 | raw_print_done (GtkPrintJob * job, gint * ret, GError * err) 197 | { 198 | if (err) 199 | { 200 | g_printerr (_("Printing failed: %s\n"), err->message); 201 | *ret = 1; 202 | } 203 | yad_exit (options.data.def_resp); 204 | } 205 | 206 | static void 207 | size_allocate_cb (GtkWidget * w, GtkAllocation * al, gpointer data) 208 | { 209 | gtk_widget_set_size_request (w, al->width, -1); 210 | } 211 | 212 | gint 213 | yad_print_run (void) 214 | { 215 | GtkWidget *dlg; 216 | GtkWidget *box, *img, *lbl; 217 | gchar *uri, *fn, *job_name = NULL; 218 | GtkPrintCapabilities pcap; 219 | GtkPrintOperationAction act = GTK_PRINT_OPERATION_ACTION_PRINT; 220 | GtkPrintSettings *print_settings = NULL; 221 | GtkPageSetup *page_setup = NULL; 222 | gint resp, ret = 0; 223 | GError *err = NULL; 224 | 225 | /* check if file is exists */ 226 | if (options.common_data.uri && options.common_data.uri[0]) 227 | { 228 | if (!g_file_test (options.common_data.uri, G_FILE_TEST_EXISTS)) 229 | { 230 | g_printerr (_("File %s not found.\n"), options.common_data.uri); 231 | return 1; 232 | } 233 | } 234 | else 235 | { 236 | g_printerr (_("Filename is not specified.\n")); 237 | return 1; 238 | } 239 | 240 | /* load previously saved print settings */ 241 | fn = g_build_filename (g_get_user_config_dir (), "yad", "print.conf", NULL); 242 | if (g_file_test (fn, G_FILE_TEST_EXISTS)) 243 | { 244 | print_settings = gtk_print_settings_new_from_file (fn, NULL); 245 | page_setup = gtk_page_setup_new_from_file (fn, NULL); 246 | } 247 | g_free (fn); 248 | 249 | if (!print_settings) 250 | print_settings = gtk_print_settings_new (); 251 | if (!page_setup) 252 | page_setup = gtk_page_setup_new (); 253 | 254 | /* create print dialog */ 255 | dlg = gtk_print_unix_dialog_new (options.data.dialog_title, NULL); 256 | gtk_window_set_type_hint (GTK_WINDOW (dlg), GDK_WINDOW_TYPE_HINT_NORMAL); 257 | gtk_print_unix_dialog_set_embed_page_setup (GTK_PRINT_UNIX_DIALOG (dlg), TRUE); 258 | pcap = GTK_PRINT_CAPABILITY_PAGE_SET | GTK_PRINT_CAPABILITY_COPIES | 259 | GTK_PRINT_CAPABILITY_COLLATE | GTK_PRINT_CAPABILITY_REVERSE | 260 | GTK_PRINT_CAPABILITY_NUMBER_UP | GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT; 261 | if (options.common_data.preview && options.print_data.type != YAD_PRINT_RAW) 262 | pcap |= GTK_PRINT_CAPABILITY_PREVIEW; 263 | gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dlg), pcap); 264 | 265 | uri = g_build_filename (g_get_current_dir (), "yad.pdf", NULL); 266 | gtk_print_settings_set (print_settings, "output-uri", g_filename_to_uri (uri, NULL, NULL)); 267 | g_free (uri); 268 | 269 | gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dlg), print_settings); 270 | gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dlg), page_setup); 271 | 272 | /* set window behavior */ 273 | gtk_widget_set_name (dlg, "yad-dialog-window"); 274 | if (options.data.sticky) 275 | gtk_window_stick (GTK_WINDOW (dlg)); 276 | gtk_window_set_resizable (GTK_WINDOW (dlg), !options.data.fixed); 277 | gtk_window_set_keep_above (GTK_WINDOW (dlg), options.data.ontop); 278 | gtk_window_set_decorated (GTK_WINDOW (dlg), !options.data.undecorated); 279 | gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), options.data.skip_taskbar); 280 | gtk_window_set_skip_pager_hint (GTK_WINDOW (dlg), options.data.skip_taskbar); 281 | 282 | /* set window size and position */ 283 | gtk_window_set_default_size (GTK_WINDOW (dlg), options.data.width, options.data.height); 284 | if (options.data.center) 285 | gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER); 286 | else if (options.data.mouse) 287 | gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); 288 | 289 | /* create yad's top box */ 290 | if (options.data.dialog_text || options.data.dialog_image) 291 | { 292 | box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); 293 | 294 | if (options.data.dialog_image) 295 | { 296 | GdkPixbuf *pb = NULL; 297 | 298 | pb = get_pixbuf (options.data.dialog_image, YAD_BIG_ICON, FALSE); 299 | img = gtk_image_new_from_pixbuf (pb); 300 | if (pb) 301 | g_object_unref (pb); 302 | 303 | gtk_widget_set_name (img, "yad-dialog-image"); 304 | gtk_box_pack_start (GTK_BOX (box), img, FALSE, FALSE, 2); 305 | } 306 | if (options.data.dialog_text) 307 | { 308 | gchar *buf = g_strcompress (options.data.dialog_text); 309 | 310 | lbl = gtk_label_new (NULL); 311 | if (!options.data.no_markup) 312 | gtk_label_set_markup (GTK_LABEL (lbl), buf); 313 | else 314 | gtk_label_set_text (GTK_LABEL (lbl), buf); 315 | gtk_widget_set_name (lbl, "yad-dialog-label"); 316 | gtk_label_set_selectable (GTK_LABEL (lbl), options.data.selectable_labels); 317 | gtk_label_set_xalign (GTK_LABEL (lbl), options.data.text_align); 318 | 319 | if (options.data.geometry || options.data.width != -1) 320 | gtk_label_set_line_wrap (GTK_LABEL (lbl), TRUE); 321 | gtk_box_pack_start (GTK_BOX (box), lbl, TRUE, TRUE, 2); 322 | g_signal_connect (G_OBJECT (lbl), "size-allocate", G_CALLBACK (size_allocate_cb), NULL); 323 | g_free (buf); 324 | } 325 | 326 | /* add tob box to dialog */ 327 | gtk_widget_show_all (box); 328 | gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), box, TRUE, TRUE, 5); 329 | gtk_box_reorder_child (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), box, 0); 330 | } 331 | 332 | do 333 | { 334 | resp = gtk_dialog_run (GTK_DIALOG (dlg)); 335 | switch (resp) 336 | { 337 | case GTK_RESPONSE_APPLY: /* ask for preview */ 338 | act = GTK_PRINT_OPERATION_ACTION_PREVIEW; 339 | case GTK_RESPONSE_OK: /* run print */ 340 | print_settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (dlg)); 341 | page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dlg)); 342 | job_name = g_strdup_printf ("yad-%s-%d", g_path_get_basename (options.common_data.uri), getpid ()); 343 | if (options.print_data.type != YAD_PRINT_RAW) 344 | { 345 | /* print text or image */ 346 | GtkPrintOperation *op = gtk_print_operation_new (); 347 | gtk_print_operation_set_unit (op, GTK_UNIT_POINTS); 348 | gtk_print_operation_set_print_settings (op, print_settings); 349 | gtk_print_operation_set_default_page_setup (op, page_setup); 350 | gtk_print_operation_set_job_name (op, job_name); 351 | 352 | switch (options.print_data.type) 353 | { 354 | case YAD_PRINT_TEXT: 355 | g_signal_connect (G_OBJECT (op), "begin-print", G_CALLBACK (begin_print_text), NULL); 356 | g_signal_connect (G_OBJECT (op), "draw-page", G_CALLBACK (draw_page_text), NULL); 357 | break; 358 | case YAD_PRINT_IMAGE: 359 | gtk_print_operation_set_n_pages (op, 1); 360 | g_signal_connect (G_OBJECT (op), "draw-page", G_CALLBACK (draw_page_image), NULL); 361 | break; 362 | default:; 363 | } 364 | 365 | if (gtk_print_operation_run (op, act, NULL, &err) == GTK_PRINT_OPERATION_RESULT_ERROR) 366 | { 367 | g_printerr (_("Printing failed: %s\n"), err->message); 368 | ret = 1; 369 | } 370 | } 371 | else 372 | { 373 | /* print raw ps or pdf data */ 374 | GtkPrinter *prnt; 375 | GtkPrintJob *job; 376 | 377 | prnt = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dlg)); 378 | 379 | if (g_str_has_suffix (options.common_data.uri, ".ps")) 380 | { 381 | if (!gtk_printer_accepts_ps (prnt)) 382 | { 383 | g_printerr (_("Printer doesn't support ps format.\n")); 384 | ret = 1; 385 | } 386 | } 387 | else if (g_str_has_suffix (options.common_data.uri, ".pdf")) 388 | { 389 | if (!gtk_printer_accepts_pdf (prnt)) 390 | { 391 | g_printerr (_("Printer doesn't support pdf format.\n")); 392 | ret = 1; 393 | } 394 | } 395 | else 396 | { 397 | g_printerr (_("This file type is not supported for raw printing.\n")); 398 | ret = 1; 399 | } 400 | if (ret == 1) 401 | break; 402 | 403 | job = gtk_print_job_new (job_name, prnt, print_settings, page_setup); 404 | if (gtk_print_job_set_source_file (job, options.common_data.uri, &err)) 405 | { 406 | gtk_print_job_send (job, (GtkPrintJobCompleteFunc) raw_print_done, &ret, NULL); 407 | gtk_main (); 408 | } 409 | else 410 | { 411 | g_printerr (_("Load source file failed: %s\n"), err->message); 412 | ret = 1; 413 | } 414 | } 415 | break; 416 | default: 417 | ret = 1; 418 | break; 419 | } 420 | } 421 | while (resp == GTK_RESPONSE_APPLY); 422 | 423 | gtk_widget_destroy (dlg); 424 | 425 | /* save print settings */ 426 | fn = g_build_filename (g_get_user_config_dir (), "yad", NULL); 427 | g_mkdir_with_parents (fn, 0700); 428 | g_free (fn); 429 | 430 | fn = g_build_filename (g_get_user_config_dir (), "yad", "print.conf", NULL); 431 | gtk_print_settings_to_file (print_settings, fn, NULL); 432 | gtk_page_setup_to_file (page_setup, fn, NULL); 433 | g_free (fn); 434 | 435 | return ret; 436 | } 437 | --------------------------------------------------------------------------------