├── data ├── meson.build ├── icons │ ├── 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 │ ├── 128x128 │ │ ├── yad.png │ │ └── Makefile.am │ ├── meson.build │ └── Makefile.am ├── misc │ ├── pfd │ ├── zenity.sh │ └── notify-send ├── yad-icon-browser.desktop.in ├── Makefile.am ├── yad.m4.in ├── yad.spec.in └── yad-tools.1 ├── Makefile.am ├── meson_options.txt ├── meson.build ├── po ├── meson.build ├── LINGUAS └── POTFILES.in ├── AUTHORS ├── .gitignore ├── TODO ├── acinclude.m4 ├── distributions.md ├── src ├── cpicker.h ├── meson.build ├── Makefile.am ├── calendar.xpm ├── about.c ├── paned.c ├── calendar.c ├── font.c ├── dnd.c ├── notebook.c ├── file.c ├── cpicker_gtk2.c ├── scale.c ├── color.c ├── picture.c ├── cpicker.c ├── entry.c ├── tools.c ├── notification.c ├── html_gtk2.c ├── browser.c ├── print.c └── progress.c ├── THANKS ├── README.md └── configure.ac /data/meson.build: -------------------------------------------------------------------------------- 1 | install_man('yad.1') 2 | 3 | subdir('icons') 4 | -------------------------------------------------------------------------------- /data/icons/16x16/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/step-/yad/HEAD/data/icons/16x16/yad.png -------------------------------------------------------------------------------- /data/icons/24x24/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/step-/yad/HEAD/data/icons/24x24/yad.png -------------------------------------------------------------------------------- /data/icons/32x32/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/step-/yad/HEAD/data/icons/32x32/yad.png -------------------------------------------------------------------------------- /data/icons/48x48/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/step-/yad/HEAD/data/icons/48x48/yad.png -------------------------------------------------------------------------------- /data/icons/96x96/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/step-/yad/HEAD/data/icons/96x96/yad.png -------------------------------------------------------------------------------- /data/icons/128x128/yad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/step-/yad/HEAD/data/icons/128x128/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 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | 2 | SUBDIRS = src po data 3 | 4 | EXTRA_DIST = COPYING ChangeLog.old NEWS README.md AUTHORS TODO THANKS 5 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('rgb', type: 'string', value: '/etc/X11/rgb.txt', description: 'Set path to rgb.txt file') 2 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('yad', 'c', version: '0.42.81', license: 'GPLv3') 2 | 3 | subdir('po') 4 | subdir('src') 5 | subdir('data') 6 | -------------------------------------------------------------------------------- /po/meson.build: -------------------------------------------------------------------------------- 1 | i18n = import('i18n') 2 | add_project_arguments('-DGETTEXT_PACKAGE="yad"', language:'c') 3 | i18n.gettext('yad') 4 | -------------------------------------------------------------------------------- /data/misc/pfd: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "WARNING: pfd is deprecated. Please use yad-tools --pfd instead" >&2 4 | exec yad-tools --pfd "$@" 5 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Victor Ananjevsky 2 | 3 | Zenity Authors: 4 | Glynn Foster 5 | Mike Newman 6 | -------------------------------------------------------------------------------- /po/LINGUAS: -------------------------------------------------------------------------------- 1 | # yad translations 2 | # 3 | # please keep this list sorted alphabetically 4 | # 5 | de 6 | es 7 | fr 8 | it 9 | pt_BR 10 | ru 11 | sk 12 | uk 13 | zh_TW 14 | -------------------------------------------------------------------------------- /data/icons/meson.build: -------------------------------------------------------------------------------- 1 | foreach size : [16, 24, 32, 48, 96, 128] 2 | install_data(f'@size@x@size@/yad.png', 3 | install_dir : f'share/icons/hicolor/@size@x@size@/apps') 4 | endforeach 5 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /po/POTFILES.in: -------------------------------------------------------------------------------- 1 | src/about.c 2 | src/calendar.c 3 | src/entry.c 4 | src/file.c 5 | src/font.c 6 | src/form.c 7 | src/html.c 8 | src/icons.c 9 | src/main.c 10 | src/notification.c 11 | src/scale.c 12 | src/list.c 13 | src/option.c 14 | src/multi-progress.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/browser.c 22 | src/notebook.c 23 | src/tools.c 24 | data/yad-icon-browser.desktop.in 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | configure 4 | build/ 5 | autom4te.cache/ 6 | .deps/ 7 | *.o 8 | *~ 9 | \#*\# 10 | aclocal.m4 11 | config.h 12 | config.h.in 13 | config.log 14 | config.status 15 | data/yad-icon-browser.desktop 16 | data/yad.m4 17 | data/yad.spec 18 | po/.intltool-merge-cache 19 | po/Makefile.in.in 20 | po/POTFILES 21 | po/*.pot 22 | po/*.gmo 23 | po/stamp-it 24 | src/yad 25 | src/yad-icon-browser 26 | src/yad-tools 27 | stamp-h1 28 | *.tar.xz 29 | build.log 30 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /data/Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = icons 2 | 3 | desktop_in_files = yad-icon-browser.desktop.in 4 | if BUILD_IB 5 | desktopdir = $(datadir)/applications 6 | desktop_DATA = $(desktop_in_files:.desktop.in=.desktop) 7 | @INTLTOOL_DESKTOP_RULE@ 8 | endif 9 | 10 | dist_man_MANS = yad.1 11 | if BUILD_TOOLS 12 | dist_man_MANS += yad-tools.1 13 | endif 14 | 15 | m4dir = $(datadir)/aclocal 16 | m4_DATA = yad.m4 17 | 18 | EXTRA_DIST = $(desktop_in_files) misc 19 | 20 | DISTCLEANFILES = $(desktop_DATA) $(m4_DATA) yad.spec 21 | -------------------------------------------------------------------------------- /acinclude.m4: -------------------------------------------------------------------------------- 1 | dnl Disable deprecated GTK+ features 2 | AC_DEFUN([GTK_DISABLE_DEPRECATED], 3 | [ 4 | AC_ARG_ENABLE(deprecated, [AC_HELP_STRING([--disable-deprecated], 5 | [Disable deprecated GTK functions])], 6 | ,[enable_deprecated=yes]) 7 | 8 | 9 | if test x$enable_deprecated = xyes 10 | then 11 | DISABLE_DEPRECATED= 12 | else 13 | DISABLE_DEPRECATED="-DG_DISABLE_DEPRECATED -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED -DPANGO_DISABLE_DEPRECATED -DGTK_DISABLE_DEPRECATED -DGSEAL_ENABLE" 14 | fi 15 | 16 | AC_SUBST(DISABLE_DEPRECATED) 17 | ]) 18 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /distributions.md: -------------------------------------------------------------------------------- 1 | # DISTRIBUTIONS KNOWN TO PACKAGE THIS FORK 2 | 3 | Submit a PR to add your distribution. 4 | 5 | * EasyOS, from version 3.0 onwards: https://easyos.org | [recipe](https://github.com/bkauler/oe-qky-scarthgap/tree/main/quirky/meta-quirky/recipes-quirky/yad0) 6 | * Fatdog64 Linux: https://distro.ibiblio.org/fatdog/web/ | [packages](https://distro.ibiblio.org/fatdog/packages) 7 | * Vanilla Dpup: https://github.com/vanilla-dpup/releases/releases | [recipe](https://github.com/vanilla-dpup/woof-CE/tree/vanilladpup-12.0.x/rootfs-petbuilds/yad) 8 | * Window Maker Live 13.2 onwards: https://wmlive.sourceforge.net/ | [Debian packages](https://github.com/step-/yad/issues/9#issuecomment-3619760779) 9 | * Woof, the Puppy Linux builder: https://github.com/puppylinux-woof-CE/woof-CE | [recipe](https://github.com/puppylinux-woof-CE/woof-CE/tree/testing/woof-code/rootfs-petbuilds/yad) 10 | 11 | -------------------------------------------------------------------------------- /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) 2023, step https://github.com/step- 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 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | src = [ 2 | 'about.c', 3 | 'calendar.c', 4 | 'color.c', 5 | 'cpicker.c', 6 | 'dnd.c', 7 | 'entry.c', 8 | 'file.c', 9 | 'font.c', 10 | 'form.c', 11 | 'icons.c', 12 | 'list.c', 13 | 'main.c', 14 | 'notebook.c', 15 | 'notification.c', 16 | 'option.c', 17 | 'paned.c', 18 | 'picture.c', 19 | 'print.c', 20 | 'progress.c', 21 | 'scale.c', 22 | 'text.c', 23 | 'util.c', 24 | ] 25 | 26 | cfg = configuration_data() 27 | 28 | cfg.set_quoted('PACKAGE_NAME', meson.project_name()) 29 | cfg.set_quoted('PACKAGE_VERSION', meson.project_version()) 30 | cfg.set_quoted('PACKAGE_URL', 'http://github.com/step-/yad') 31 | cfg.set_quoted('RGB_FILE', get_option('rgb')) 32 | cfg.set('HAVE_TRAY', 1) 33 | 34 | dep = [ 35 | meson.get_compiler('c').find_library('m'), 36 | dependency('gtk+-3.0'), 37 | dependency('gtk+-unix-print-3.0'), 38 | ] 39 | 40 | gtk_layer_shell = dependency('gtk-layer-shell-0', required: false) 41 | if gtk_layer_shell.found() 42 | dep += gtk_layer_shell 43 | cfg.set('HAVE_GTK_LAYER_SHELL', 1) 44 | endif 45 | 46 | # TODO add html widget (webkit2gtk-4.1 && gtk3, default false) 47 | 48 | configure_file( 49 | output : 'config.h', 50 | configuration : cfg, 51 | ) 52 | 53 | yad = executable( 54 | 'yad', 55 | src, 56 | dependencies: dep, 57 | install: true, 58 | ) 59 | -------------------------------------------------------------------------------- /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 = \ 2 | -DLOCALEDIR=\""$(datadir)/locale"\" \ 3 | @DISABLE_DEPRECATED@ 4 | 5 | bin_PROGRAMS = yad 6 | 7 | if GTK2 8 | CPICKER_SOURCES = cpicker_gtk2.c cpicker.h 9 | else 10 | CPICKER_SOURCES = cpicker.c cpicker.h 11 | endif 12 | 13 | yad_SOURCES = \ 14 | about.c \ 15 | calendar.c \ 16 | color.c \ 17 | dnd.c \ 18 | entry.c \ 19 | file.c \ 20 | font.c \ 21 | form.c \ 22 | icons.c \ 23 | list.c \ 24 | notebook.c \ 25 | option.c \ 26 | paned.c \ 27 | picture.c \ 28 | print.c \ 29 | progress.c \ 30 | scale.c \ 31 | text.c \ 32 | util.c \ 33 | main.c \ 34 | yad.h \ 35 | calendar.xpm \ 36 | $(CPICKER_SOURCES) 37 | 38 | if TRAY 39 | yad_SOURCES += notification.c 40 | endif 41 | 42 | if HTML 43 | if GTK2 44 | yad_SOURCES += html_gtk2.c 45 | else 46 | yad_SOURCES += html.c 47 | endif 48 | endif 49 | 50 | yad_CFLAGS = $(GTK_CFLAGS) $(HTML_CFLAGS) $(SPELL_CFLAGS) $(SOURCEVIEW_CFLAGS) 51 | yad_LDADD = $(GTK_LIBS) $(HTML_LIBS) $(SPELL_LIBS) $(SOURCEVIEW_LIBS) 52 | 53 | if GMODULE 54 | yad_CFLAGS += $(GMODULE_CFLAGS) 55 | yad_LDADD += $(GMODULE_LIBS) 56 | endif 57 | 58 | if BUILD_TOOLS 59 | bin_PROGRAMS += yad-tools 60 | 61 | yad_tools_SOURCES = tools.c $(CPICKER_SOURCES) 62 | yad_tools_CFLAGS = $(GTK_CFLAGS) $(SPELL_CFLAGS) $(SOURCEVIEW_CFLAGS) 63 | yad_tools_LDADD = $(GTK_LIBS) $(SPELL_LIBS) $(SOURCEVIEW_LIBS) 64 | endif 65 | 66 | if BUILD_IB 67 | bin_PROGRAMS += yad-icon-browser 68 | 69 | yad_icon_browser_SOURCES = browser.c 70 | yad_icon_browser_CFLAGS = $(GTK_CFLAGS) 71 | yad_icon_browser_LDADD = $(GTK_LIBS) 72 | endif 73 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /data/yad-tools.1: -------------------------------------------------------------------------------- 1 | .TH YAD-TOOLS "1" "April 2021" "yad-tools" "User Commands" 2 | 3 | .SH NAME 4 | yad-tools \- show miscellaneous information. 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 useful 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 a 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 an icon name. 25 | .TP 26 | \fB\-c\fR, \fB\-\-color\fR 27 | This mode is intended for working with colors. 28 | .TP 29 | .B \-\-show-langs 30 | Show list of available languages for spell checking. It only works if yad was built with \fIGtkspell3\fP support. 31 | .TP 32 | .B \-\-show-themes 33 | Show list of available GtkSourceView themes. It only works if yad was 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 the 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 the 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 the specified icon theme instead of the default. 56 | 57 | .SS Color mode options 58 | .TP 59 | \fB\-\-pick\fP 60 | Pick screen pixel 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 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include "yad.h" 22 | 23 | gint 24 | yad_about (void) 25 | { 26 | GtkWidget *dialog; 27 | const gchar *const authors_et_al[] = { 28 | "Victor Ananjevsky ", 29 | PACKAGE_URL " ", 30 | "step http://github.com/step-/yad/" " ", 31 | NULL 32 | }; 33 | gchar * roles[] = { 34 | _("Author:\n\t%s"), 35 | _("Homepage:\n\t%s"), 36 | _("Maintainer GTK+ 2:\n\t%s"), 37 | NULL 38 | }; 39 | const gchar *translators = N_("translator-credits"); 40 | const gchar *license = 41 | N_("YAD is free software; you can redistribute it and/or modify " 42 | "it under the terms of the GNU General Public License as published by " 43 | "the Free Software Foundation; either version 3 of the License, or " 44 | "(at your option) any later version.\n\n" 45 | "YAD is distributed in the hope that it will be useful, " 46 | "but WITHOUT ANY WARRANTY; without even the implied warranty of " 47 | "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " 48 | "GNU General Public License for more details.\n\n" 49 | "You should have received a copy of the GNU General Public License " 50 | "along with YAD. If not, see http://www.gnu.org/licenses/\x20."); 51 | 52 | gchar **p, **q; 53 | for (p = (gchar **) authors_et_al, q = roles; *p && *q; p++, q++) 54 | *q = g_strdup_printf (*q, *p); 55 | 56 | gchar *comments = g_strdup_printf (_("Yet Another Dialog\n" 57 | "(show dialog boxes from shell scripts)\n" 58 | "\nBased on Zenity code\n\n" 59 | #ifdef HAVE_HTML 60 | "Built with Webkit\n" 61 | #endif 62 | #ifdef HAVE_SOURCEVIEW 63 | "Built with GtkSourceView\n" 64 | #endif 65 | #ifdef HAVE_SPELL 66 | "Built with GtkSpell\n" 67 | #endif 68 | "Using GTK+ %d.%d.%d\n\n" 69 | "CLICK CREDITS FOR LINKS\n"), 70 | gtk_major_version, gtk_minor_version, gtk_micro_version); 71 | 72 | dialog = gtk_about_dialog_new (); 73 | gtk_window_set_icon_name (GTK_WINDOW (dialog), "yad"); 74 | g_object_set (G_OBJECT (dialog), 75 | "name", PACKAGE_NAME, 76 | "version", PACKAGE_VERSION, 77 | "copyright", "Copyright \xc2\xa9 2008-2019, Victor Ananjevsky\n" 78 | "Copyright \xc2\xa9 2019-2025, step", 79 | "comments", comments, 80 | "authors", roles, 81 | "website", "", 82 | "translator-credits", translators, 83 | "wrap-license", TRUE, 84 | "license", license, 85 | "logo-icon-name", "yad", 86 | NULL); 87 | 88 | return gtk_dialog_run (GTK_DIALOG (dialog)); 89 | } 90 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "yad.h" 36 | 37 | static GtkWidget *paned; 38 | 39 | GtkWidget * 40 | paned_create_widget (GtkWidget * dlg) 41 | { 42 | GtkWidget *w, *s; 43 | 44 | /* get shared memory */ 45 | tabs = get_tabs (options.common_data.key, TRUE); 46 | if (!tabs) 47 | exit (-1); 48 | 49 | /* create widget */ 50 | #if !GTK_CHECK_VERSION(3,0,0) 51 | if (options.paned_data.orient == GTK_ORIENTATION_HORIZONTAL) 52 | paned = w = gtk_hpaned_new (); 53 | else 54 | paned = w = gtk_vpaned_new (); 55 | #else 56 | paned = w = gtk_paned_new (options.paned_data.orient); 57 | #endif 58 | gtk_widget_set_name (w, "yad-paned-widget"); 59 | 60 | gtk_paned_set_position (GTK_PANED (w), options.paned_data.splitter); 61 | 62 | s = gtk_socket_new (); 63 | gtk_paned_add1 (GTK_PANED (w), s); 64 | g_object_set_data (G_OBJECT (w), "s1", s); 65 | 66 | s = gtk_socket_new (); 67 | gtk_paned_add2 (GTK_PANED (w), s); 68 | g_object_set_data (G_OBJECT (w), "s2", s); 69 | 70 | return w; 71 | } 72 | 73 | void 74 | paned_swallow_childs (void) 75 | { 76 | GtkWidget *s1, *s2; 77 | 78 | s1 = GTK_WIDGET (g_object_get_data (G_OBJECT (paned), "s1")); 79 | s2 = GTK_WIDGET (g_object_get_data (G_OBJECT (paned), "s2")); 80 | 81 | /* wait until all children are registered */ 82 | while (!tabs[1].xid || !tabs[2].xid) 83 | usleep (1000); 84 | 85 | if (tabs[1].pid != -1) 86 | gtk_socket_add_id (GTK_SOCKET (s1), tabs[1].xid); 87 | if (tabs[2].pid != -1) 88 | gtk_socket_add_id (GTK_SOCKET (s2), tabs[2].xid); 89 | } 90 | 91 | void 92 | paned_print_result (void) 93 | { 94 | if (tabs[1].pid != -1) 95 | kill (tabs[1].pid, SIGUSR1); 96 | if (tabs[2].pid != -1) 97 | kill (tabs[2].pid, SIGUSR1); 98 | } 99 | 100 | void 101 | paned_close_childs (void) 102 | { 103 | guint i; 104 | struct shmid_ds buf; 105 | gboolean is_running = TRUE; 106 | 107 | if (tabs[1].pid != -1) 108 | kill (tabs[1].pid, SIGUSR2); 109 | if (tabs[2].pid != -1) 110 | kill (tabs[2].pid, SIGUSR2); 111 | 112 | /* wait for stop subprocesses */ 113 | while (is_running) 114 | { 115 | is_running = FALSE; 116 | for (i = 1; i < 3; i++) 117 | { 118 | if (tabs[i].pid != -1 && kill (tabs[i].pid, 0) == 0) 119 | { 120 | is_running = TRUE; 121 | break; 122 | } 123 | } 124 | if (is_running) 125 | usleep (1000); 126 | } 127 | 128 | /* cleanup shared memory */ 129 | shmctl (tabs[0].pid, IPC_RMID, &buf); 130 | shmdt (tabs); 131 | } 132 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | 23 | #include "yad.h" 24 | 25 | static GtkWidget *calendar; 26 | 27 | static GHashTable *details; 28 | 29 | static void 30 | parse_details () 31 | { 32 | FILE *f; 33 | 34 | details = g_hash_table_new (g_str_hash, g_str_equal); 35 | 36 | /* open details file */ 37 | f = fopen (options.calendar_data.details, "r"); 38 | if (f == NULL) 39 | { 40 | g_printerr (_("Cannot open file '%s': %s\n"), options.common_data.uri, g_strerror (errno)); 41 | return; 42 | } 43 | 44 | /* read details file */ 45 | while (!feof (f)) 46 | { 47 | gchar buf[4096], **dtl; 48 | 49 | /* read string */ 50 | memset (buf, 0, 4096); 51 | fgets (buf, 4096, f); 52 | if (strlen (buf) > 0) 53 | { 54 | 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 | return str; 80 | } 81 | 82 | static void 83 | double_click_cb (GtkWidget * w, gpointer data) 84 | { 85 | if (options.plug == -1) 86 | yad_exit (options.data.def_resp); 87 | } 88 | 89 | GtkWidget * 90 | calendar_create_widget (GtkWidget * dlg) 91 | { 92 | GtkWidget *w; 93 | gint cal_opts; 94 | 95 | w = calendar = gtk_calendar_new (); 96 | gtk_widget_set_name (w, "yad-calendar-widget"); 97 | 98 | if (options.calendar_data.month > 0 || options.calendar_data.year > 0) 99 | gtk_calendar_select_month (GTK_CALENDAR (w), options.calendar_data.month - 1, options.calendar_data.year); 100 | if (options.calendar_data.day > 0) 101 | gtk_calendar_select_day (GTK_CALENDAR (w), options.calendar_data.day); 102 | 103 | if (options.calendar_data.details) 104 | { 105 | parse_details (); 106 | gtk_calendar_set_detail_func (GTK_CALENDAR (w), get_details, NULL, NULL); 107 | } 108 | 109 | cal_opts = GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES; 110 | if (options.calendar_data.weeks) 111 | cal_opts |= GTK_CALENDAR_SHOW_WEEK_NUMBERS; 112 | gtk_calendar_set_display_options (GTK_CALENDAR (w), cal_opts); 113 | 114 | g_signal_connect (w, "day-selected-double-click", G_CALLBACK (double_click_cb), dlg); 115 | 116 | return w; 117 | } 118 | 119 | void 120 | calendar_print_result (void) 121 | { 122 | guint day, month, year; 123 | gchar time_string[128]; 124 | GDate *date = NULL; 125 | 126 | gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day); 127 | date = g_date_new_dmy (day, month + 1, year); 128 | g_date_strftime (time_string, 127, options.common_data.date_format, date); 129 | g_print ("%s\n", time_string); 130 | } 131 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include "yad.h" 22 | 23 | static GtkWidget *font; 24 | 25 | static void 26 | realize_cb (GtkWidget * w, gpointer d) 27 | { 28 | #if GTK_CHECK_VERSION(3,2,0) 29 | gtk_font_chooser_set_font (GTK_FONT_CHOOSER (w), options.common_data.font); 30 | #else 31 | gtk_font_selection_set_font_name (GTK_FONT_SELECTION (w), options.common_data.font); 32 | #endif 33 | } 34 | 35 | GtkWidget * 36 | font_create_widget (GtkWidget * dlg) 37 | { 38 | GtkWidget *w; 39 | 40 | #if GTK_CHECK_VERSION(3,2,0) 41 | w = font = gtk_font_chooser_widget_new (); 42 | #else 43 | w = font = gtk_font_selection_new (); 44 | #endif 45 | gtk_widget_set_name (w, "yad-font-widget"); 46 | 47 | if (options.font_data.preview) 48 | #if GTK_CHECK_VERSION(3,2,0) 49 | gtk_font_chooser_set_preview_text (GTK_FONT_CHOOSER (w), options.font_data.preview); 50 | #else 51 | gtk_font_selection_set_preview_text (GTK_FONT_SELECTION (w), options.font_data.preview); 52 | #endif 53 | 54 | /* font must be set after widget inserted in toplevel */ 55 | if (options.common_data.font) 56 | g_signal_connect_after (G_OBJECT (w), "realize", G_CALLBACK (realize_cb), NULL); 57 | 58 | return w; 59 | } 60 | 61 | void 62 | font_print_result (void) 63 | { 64 | if (options.font_data.separate_output) 65 | { 66 | PangoFontFace *face; 67 | PangoFontFamily *family; 68 | gint size; 69 | 70 | #if GTK_CHECK_VERSION(3,2,0) 71 | face = gtk_font_chooser_get_font_face (GTK_FONT_CHOOSER (font)); 72 | family = gtk_font_chooser_get_font_family (GTK_FONT_CHOOSER (font)); 73 | size = gtk_font_chooser_get_font_size (GTK_FONT_CHOOSER (font)); 74 | #else 75 | face = gtk_font_selection_get_face (GTK_FONT_SELECTION (font)); 76 | family = gtk_font_selection_get_family (GTK_FONT_SELECTION (font)); 77 | size = gtk_font_selection_get_size (GTK_FONT_SELECTION (font)); 78 | #endif 79 | 80 | if (options.common_data.quoted_output) 81 | { 82 | gchar *q1 = g_shell_quote (pango_font_family_get_name (family)); 83 | gchar *q2 = g_shell_quote (pango_font_face_get_face_name (face)); 84 | 85 | g_printf ("%s%s%s%s%d\n", q1, options.common_data.separator, q2, 86 | options.common_data.separator, size / PANGO_SCALE); 87 | 88 | g_free (q1); 89 | g_free (q2); 90 | } 91 | else 92 | { 93 | g_printf ("%s%s%s%s%d\n", pango_font_family_get_name (family), options.common_data.separator, 94 | pango_font_face_get_face_name (face), options.common_data.separator, size / PANGO_SCALE); 95 | } 96 | } 97 | else 98 | { 99 | #if GTK_CHECK_VERSION(3,2,0) 100 | gchar *fn = gtk_font_chooser_get_font (GTK_FONT_CHOOSER (font)); 101 | #else 102 | gchar *fn = gtk_font_selection_get_font_name (GTK_FONT_SELECTION (font)); 103 | #endif 104 | 105 | if (options.common_data.quoted_output) 106 | { 107 | gchar *buf = g_shell_quote (fn); 108 | g_printf ("%s\n", buf); 109 | g_free (buf); 110 | } 111 | else 112 | g_printf ("%s\n", fn); 113 | 114 | g_free (fn); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include "yad.h" 22 | 23 | static void 24 | drop_data_cb (GtkWidget * w, GdkDragContext * dc, gint x, gint y, 25 | GtkSelectionData * sel, guint info, guint t, gpointer data) 26 | { 27 | GdkAtom stgt; 28 | static guint drop_cnt = 0; 29 | 30 | stgt = gtk_selection_data_get_target (sel); 31 | 32 | if (gtk_targets_include_uri (&stgt, 1)) 33 | { 34 | gchar **uris; 35 | gint i = 0; 36 | 37 | uris = gtk_selection_data_get_uris (sel); 38 | if (!uris) 39 | return; 40 | 41 | while (uris[i]) 42 | { 43 | gchar *dstr = g_uri_unescape_string (uris[i], NULL); 44 | if (options.common_data.command) 45 | { 46 | gchar *action; 47 | 48 | if (g_strstr_len (options.common_data.command, -1, "%s")) 49 | action = g_strdup_printf (options.common_data.command, dstr); 50 | else 51 | action = g_strdup_printf ("%s '%s'", options.common_data.command, dstr); 52 | run_command_async (action); 53 | g_free (action); 54 | } 55 | else 56 | { 57 | g_printf ("%s\n", dstr); 58 | fflush (stdout); 59 | } 60 | g_free (dstr); 61 | i++; 62 | } 63 | g_strfreev (uris); 64 | } 65 | else if (gtk_targets_include_text (&stgt, 1)) 66 | { 67 | guchar *str = gtk_selection_data_get_text (sel); 68 | if (str) 69 | { 70 | gchar *dstr = g_uri_unescape_string ((const gchar *) str, NULL); 71 | if (options.common_data.command) 72 | { 73 | gchar *action, *arg; 74 | 75 | arg = g_shell_quote (dstr); 76 | if (g_strstr_len (options.common_data.command, -1, "%s")) 77 | action = g_strdup_printf (options.common_data.command, arg); 78 | else 79 | action = g_strdup_printf ("%s %s", options.common_data.command, arg); 80 | g_free (arg); 81 | 82 | run_command_async (action); 83 | g_free (action); 84 | } 85 | else 86 | { 87 | g_printf ("%s\n", dstr); 88 | fflush (stdout); 89 | } 90 | g_free (dstr); 91 | g_free (str); 92 | } 93 | } 94 | 95 | if (options.dnd_data.exit_on_drop) 96 | { 97 | drop_cnt++; 98 | if (drop_cnt == options.dnd_data.exit_on_drop) 99 | yad_exit (options.data.def_resp); 100 | } 101 | } 102 | 103 | void 104 | dnd_init (GtkWidget * w) 105 | { 106 | GtkTargetList *tlist; 107 | GtkTargetEntry *tgts; 108 | gint ntgts; 109 | 110 | tlist = gtk_target_list_new (NULL, 0); 111 | gtk_target_list_add_uri_targets (tlist, 0); 112 | gtk_target_list_add_text_targets (tlist, 0); 113 | 114 | tgts = gtk_target_table_new_from_list (tlist, &ntgts); 115 | 116 | gtk_drag_dest_set (w, GTK_DEST_DEFAULT_ALL, tgts, ntgts, GDK_ACTION_COPY | GDK_ACTION_MOVE); 117 | g_signal_connect (G_OBJECT (w), "drag_data_received", G_CALLBACK (drop_data_cb), NULL); 118 | 119 | gtk_target_table_free (tgts, ntgts); 120 | gtk_target_list_unref (tlist); 121 | 122 | /* set tooltip */ 123 | if (options.dnd_data.tooltip) 124 | { 125 | if (!options.data.no_markup) 126 | gtk_widget_set_tooltip_markup (w, options.data.dialog_text); 127 | else 128 | gtk_widget_set_tooltip_text (w, options.data.dialog_text); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Yet Another Dialog -- GTK+-2 Maintenance Branch 2 | ==================== 3 | 4 | Use yad (yet another dialog) in shell scripts to displays GTK+ dialogs involving messages, lists, forms and several other commonly-used interface elements. 5 | 6 | Summary 7 | ------- 8 | 9 | [This](https://github.com/step-/yad) project is an independent fork of the [parent project](https://github.com/v1cont/yad). 10 | 11 | This project is licensed under the GNU GPL3 license, see _License and copyright_ section in [this page](feature-comparison.md). 12 | 13 | Project goals: 14 | 15 | * Overwhelmingly, maintain compatibility with GTK+-2. 16 | * Build against either GTK+-2 or GTK+-3. The two builds provide the same features. 17 | * Backport features from the parent project. 18 | * Introduce original features. 19 | 20 | 100% compatibility with the parent project is not a goal but keeping reasonably compatible still informs my decisions. 21 | [Feature comparison](feature-comparison.md) 22 | 23 | Several Linux [distributions](distributions.md) that still depend on GTK+-2 include a binary derived from this fork. 24 | 25 | History 26 | ------- 27 | 28 | The parent project removed GTK+-2 support in version 1.0. 29 | This repository was forked from the 0.42.0 release (d0021d0 February 2019) with the goal to continue GTK+-2 support, mainly for the benefit of the [Fatdog64](http://distro.ibiblio.org/fatdog/web/) Linux distribution. 30 | With time this fork has reached several other Linux [distributions](distributions.md) that need a GTK+-2 yad package. 31 | 32 | Scope 33 | ----- 34 | 35 | In the spirit of a maintainance project, fixing bugs takes precedence. 36 | New features can be added as my time permits but only if they are tested with, and work equally well for, GTK+-2 and GTK+-3. 37 | New features are introduced as either backports from the parent project or, more rarely, as original features. You can read all about this in the [feature comparison](feature-comparison.md) page. 38 | 39 | Contributions and pull requests (PR) are always welcome! 40 | 41 | Naming Hell 42 | ----------- 43 | 44 | This repository is named `yad`, same as its parent project's. Both projects build a binary file named `yad`. 45 | [Fatdog64](http://distro.ibiblio.org/fatdog/web/) renames the binary `yad_gtk2` or `yad_gtk3`, according to the build, and only ships `yad_gtk2`, with a symbolic link in /usr/bin from name `yad` to target `yad_gtk2`. The Fatdog64 package repository provides packages `yad_gtk2`, `yad_gtk3`, `yad_doc` and `yad_ultimate`, which is Fatdog64's package name for the parent project (and the parent project's binary is named `yadu`). 46 | 47 | For short I will use **yadL** for the products of this fork, and **yadU** for the parent project. 48 | 49 | Building yadL from Git 50 | ---------------------- 51 | 52 | This fork's default branch is named `maintain-gtk2`. All development takes place in the default branch. 53 | 54 | Get the latest source code with command: 55 | 56 | ```sh 57 | git clone https://github.com/step-/yad.git maintain-gtk2 58 | ``` 59 | 60 | Generate build scripts, configure and build the project: 61 | 62 | ```sh 63 | cd maintain-gtk2 && 64 | git checkout maintain-gtk2 && 65 | autoreconf -ivf && 66 | intltoolize && 67 | ./configure && 68 | make && 69 | : install with: make install 70 | ``` 71 | 72 | To build successfully you may need to install the following packages: 73 | 74 | * GNU Autotools (https://www.gnu.org/software/autoconf/ http://www.gnu.org/software/automake/) 75 | * Intltool >= 0.40.0 (http://freedesktop.org/wiki/Software/intltool/) 76 | * GTK+-2 >= 2.24.0 (http://www.gtk.org) 77 | * GTK+-3 >= 3.22.0 (http://www.gtk.org) 78 | 79 | with appropriate *-dev* packages depending on your distro. 80 | 81 | When you run `configure` you can pass some options to build yad with the following libraries: 82 | 83 | * GtkSourceView - for syntax highlighting in the text-info dialog (https://wiki.gnome.org/Projects/GtkSourceView) 84 | * GtkSpell3 - for spell checkinging text fields (http://gtkspell.sourceforge.net/) 85 | * Webkit - for the HTML dialog widget (http://webkitgtk.org) 86 | 87 | Distributions 88 | ------------- 89 | 90 | Distributions known to package this fork: read [distributions](distributions). 91 | 92 | Links 93 | ----- 94 | 95 | * [yadL development](https://github.com/step-/yad) 96 | * [yadL wiki](https://github.com/step-/yad/wiki) 97 | * [yad thread on Puppy Linux old forum](https://forum.puppylinux.com/viewtopic.php?t=216) 98 | * [yad thread on Puppy Linux forum](https://forum.puppylinux.com/viewtopic.php?t=3922) 99 | * [yadU development](https://github.com/v1cont/yad) 100 | * [yadU complex examples](https://github.com/v1cont/yad/wiki/YAD-Examples) 101 | * [yadU mailing list](http://groups.google.com/group/yad-common) 102 | 103 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | #include "yad.h" 36 | 37 | static GtkWidget *notebook; 38 | 39 | GtkWidget * 40 | notebook_create_widget (GtkWidget * dlg) 41 | { 42 | GtkWidget *w; 43 | GSList *tab; 44 | 45 | /* get shared memory */ 46 | tabs = get_tabs (options.common_data.key, TRUE); 47 | if (!tabs) 48 | exit (-1); 49 | 50 | /* create widget */ 51 | w = notebook = gtk_notebook_new (); 52 | gtk_widget_set_name (w, "yad-notebook-widget"); 53 | gtk_notebook_set_tab_pos (GTK_NOTEBOOK (w), options.notebook_data.pos); 54 | gtk_container_set_border_width (GTK_CONTAINER (w), 5); 55 | 56 | /* add tabs */ 57 | for (tab = options.notebook_data.tabs; tab; tab = tab->next) 58 | { 59 | GtkWidget *a, *s; 60 | 61 | SETUNDEPR (a, gtk_alignment_new, 0.5, 0.5, 1, 1); 62 | UNDEPR (gtk_alignment_set_padding, GTK_ALIGNMENT (a), 63 | options.notebook_data.borders, options.notebook_data.borders, 64 | options.notebook_data.borders, options.notebook_data.borders); 65 | 66 | s = gtk_socket_new (); 67 | gtk_container_add (GTK_CONTAINER (a), s); 68 | g_object_set_data (G_OBJECT (a), "socket", s); 69 | 70 | gtk_notebook_append_page (GTK_NOTEBOOK (w), a, get_label ((gchar *) tab->data, 0, s)); 71 | gtk_container_child_set( GTK_CONTAINER (w), a, "tab-expand", options.notebook_data.expand, NULL); 72 | } 73 | 74 | return w; 75 | } 76 | 77 | void 78 | notebook_swallow_childs (void) 79 | { 80 | guint i, n_tabs; 81 | gboolean all_registered; 82 | 83 | n_tabs = g_slist_length (options.notebook_data.tabs); 84 | 85 | /* wait until all children are registered */ 86 | do 87 | { 88 | all_registered = TRUE; 89 | for (i = 1; i <= n_tabs; i++) 90 | if (!tabs[i].xid) 91 | { 92 | all_registered = FALSE; 93 | break; 94 | } 95 | if (!all_registered) 96 | usleep (1000); 97 | } 98 | while (!all_registered); 99 | 100 | for (i = 1; i <= n_tabs; i++) 101 | { 102 | GtkWidget *s = 103 | GTK_WIDGET (g_object_get_data 104 | (G_OBJECT (gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), i - 1)), "socket")); 105 | 106 | if (tabs[i].pid != -1) 107 | gtk_socket_add_id (GTK_SOCKET (s), tabs[i].xid); 108 | } 109 | 110 | /* set active tab */ 111 | if (options.notebook_data.active > 0) 112 | gtk_notebook_set_current_page (GTK_NOTEBOOK (notebook), options.notebook_data.active - 1); 113 | } 114 | 115 | void 116 | notebook_print_result (void) 117 | { 118 | guint i, n_tabs; 119 | 120 | n_tabs = g_slist_length (options.notebook_data.tabs); 121 | for (i = 1; i <= n_tabs; i++) 122 | { 123 | if (tabs[i].pid != -1) 124 | kill (tabs[i].pid, SIGUSR1); 125 | } 126 | } 127 | 128 | void 129 | notebook_close_childs (void) 130 | { 131 | guint i, n_tabs, signal, count; 132 | struct shmid_ds buf; 133 | gboolean is_running; 134 | 135 | n_tabs = g_slist_length (options.notebook_data.tabs); 136 | for (i = 1; i <= n_tabs; i++) 137 | { 138 | if (tabs[i].pid != -1) 139 | kill (tabs[i].pid, SIGUSR2); 140 | else 141 | break; 142 | } 143 | 144 | /* counted wait for subprocesses to exit */ 145 | signal = count = 0; 146 | do 147 | { 148 | is_running = FALSE; 149 | for (i = 1; i <= n_tabs; i++) 150 | { 151 | if (tabs[i].pid != -1 && kill (tabs[i].pid, signal) == 0) 152 | { 153 | is_running = TRUE; 154 | break; 155 | } 156 | } 157 | 158 | if (is_running) 159 | { 160 | usleep (1000); 161 | /* force subprocesses to exit after 10 s timeout */ 162 | if (++count > 10000) 163 | signal = SIGTERM; 164 | } 165 | } 166 | while (is_running); 167 | 168 | /* cleanup shared memory */ 169 | shmctl (tabs[0].pid, IPC_RMID, &buf); 170 | shmdt (tabs); 171 | } 172 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include "yad.h" 22 | 23 | static GtkWidget *filechooser; 24 | 25 | static void 26 | file_activated_cb (GtkFileChooser * chooser, gpointer data) 27 | { 28 | if (options.plug == -1) 29 | yad_exit (options.data.def_resp); 30 | } 31 | 32 | gboolean 33 | file_confirm_overwrite (GtkWidget * dlg) 34 | { 35 | if (options.file_data.save && options.file_data.confirm_overwrite && !options.common_data.multi) 36 | { 37 | gchar *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (filechooser)); 38 | 39 | if (g_file_test (filename, G_FILE_TEST_EXISTS)) 40 | { 41 | GtkWidget *d; 42 | gint r; 43 | gchar *buf; 44 | 45 | buf = g_strcompress (options.file_data.confirm_text); 46 | d = gtk_message_dialog_new (GTK_WINDOW (dlg), GTK_DIALOG_DESTROY_WITH_PARENT, 47 | GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", buf); 48 | g_free (buf); 49 | r = gtk_dialog_run (GTK_DIALOG (d)); 50 | gtk_widget_destroy (d); 51 | if (r != GTK_RESPONSE_YES) 52 | return FALSE; 53 | } 54 | } 55 | 56 | return TRUE; 57 | } 58 | 59 | GtkWidget * 60 | file_create_widget (GtkWidget * dlg) 61 | { 62 | GtkWidget *w; 63 | GList *filt; 64 | GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; 65 | 66 | if (options.file_data.directory) 67 | { 68 | if (options.file_data.save) 69 | action = GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER; 70 | else 71 | action = GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; 72 | } 73 | else 74 | { 75 | if (options.file_data.save) 76 | action = GTK_FILE_CHOOSER_ACTION_SAVE; 77 | } 78 | 79 | w = filechooser = gtk_file_chooser_widget_new (action); 80 | gtk_widget_set_name (w, "yad-file-widget"); 81 | 82 | if (options.common_data.uri) 83 | { 84 | if (!options.file_data.directory && g_file_test (options.common_data.uri, G_FILE_TEST_IS_DIR)) 85 | gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), options.common_data.uri); 86 | else 87 | { 88 | gchar *dir = g_path_get_dirname (options.common_data.uri); 89 | 90 | if (g_path_is_absolute (options.common_data.uri) == TRUE) 91 | gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), dir); 92 | 93 | if (options.common_data.uri[strlen (options.common_data.uri) - 1] != '/') 94 | { 95 | gchar *basename = g_path_get_basename (options.common_data.uri); 96 | if (options.file_data.save) 97 | gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (w), basename); 98 | else 99 | gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (w), options.common_data.uri); 100 | g_free (basename); 101 | } 102 | g_free (dir); 103 | } 104 | } 105 | else 106 | gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (w), g_get_current_dir ()); 107 | 108 | if (options.common_data.multi) 109 | gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (w), TRUE); 110 | 111 | /* add preview */ 112 | if (options.common_data.preview) 113 | { 114 | GtkWidget *p = gtk_image_new (); 115 | gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (w), p); 116 | g_signal_connect (w, "update-preview", G_CALLBACK (update_preview), p); 117 | } 118 | 119 | /* add filters */ 120 | for (filt = options.common_data.filters; filt; filt = filt->next) 121 | gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (w), GTK_FILE_FILTER (filt->data)); 122 | 123 | g_signal_connect (w, "map", G_CALLBACK (gtk_file_chooser_set_show_hidden), GINT_TO_POINTER (options.common_data.show_hidden)); 124 | g_signal_connect (w, "file-activated", G_CALLBACK (file_activated_cb), dlg); 125 | 126 | return w; 127 | } 128 | 129 | void 130 | file_print_result (void) 131 | { 132 | GSList *selections, *iter; 133 | 134 | selections = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (filechooser)); 135 | for (iter = selections; iter != NULL; iter = iter->next) 136 | { 137 | if (options.common_data.quoted_output) 138 | { 139 | gchar *buf = g_shell_quote (g_filename_to_utf8 ((gchar *) iter->data, -1, NULL, NULL, NULL)); 140 | g_printf ("%s", buf); 141 | g_free (buf); 142 | } 143 | else 144 | g_printf ("%s", g_filename_to_utf8 ((gchar *) iter->data, -1, NULL, NULL, NULL)); 145 | g_free (iter->data); 146 | if (iter->next != NULL) 147 | g_printf ("%s", options.common_data.separator); 148 | } 149 | g_printf ("\n"); 150 | g_slist_free (selections); 151 | } 152 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # write PACKAGE_URL as "http" not "https" for About dialog to display a clickable link in the Credits tab. 2 | AC_INIT([YAD], [0.42.87], [https://github.com/step-/yad/issues], yad, [http://github.com/step-/yad]) 3 | AC_CONFIG_AUX_DIR([build]) 4 | 5 | AM_INIT_AUTOMAKE([1.11 foreign dist-xz no-dist-gzip]) 6 | AM_SILENT_RULES([yes]) 7 | 8 | AC_PREREQ([2.59]) 9 | 10 | AC_CONFIG_HEADERS([config.h]) 11 | AC_CONFIG_SRCDIR([src]) 12 | 13 | AM_MAINTAINER_MODE 14 | 15 | IT_PROG_INTLTOOL([0.40.0]) 16 | 17 | AC_PROG_CC 18 | 19 | AC_ARG_WITH([gtk], 20 | [AS_HELP_STRING([--with-gtk=gtk2|gtk3],[set the GTK+ version to use (default - gtk2)])], 21 | [case "$with_gtk" in 22 | gtk2|gtk3) ;; 23 | *) AC_MSG_ERROR([invalid gtk version specified]) ;; 24 | esac], 25 | [with_gtk=gtk2]) 26 | 27 | case "$with_gtk" in 28 | gtk3) 29 | GTK_MODULE="gtk+-3.0" 30 | GTK_REQUIRED="3.22.0" 31 | GTK_PRINT="gtk+-unix-print-3.0" 32 | WEBKIT="webkit2gtk-4.1" 33 | SPELL="gtkspell3-3.0" 34 | SOURCEVIEW="gtksourceview-3.0" 35 | ;; 36 | gtk2) 37 | GTK_MODULE="gtk+-2.0" 38 | GTK_REQUIRED="2.24.0" 39 | GTK_PRINT="gtk+-unix-print-2.0" 40 | WEBKIT="webkit-1.0" 41 | SPELL="gtkspell3-2.0" 42 | SOURCEVIEW="gtksourceview-2.0" 43 | ;; 44 | esac 45 | PKG_CHECK_MODULES([GTK], [$GTK_MODULE >= $GTK_REQUIRED $GTK_PRINT]) 46 | AC_SUBST([GTK_CFLAGS]) 47 | AC_SUBST([GTK_LIBS]) 48 | AM_CONDITIONAL([GTK2], [test x$with_gtk = xgtk2]) 49 | 50 | GTK_DISABLE_DEPRECATED 51 | 52 | dnl rgb.txt 53 | AC_ARG_WITH([rgb], 54 | [AS_HELP_STRING([--with-rgb=PATH], 55 | [set path to rgb.txt file (default - /etc/X11/rgb.txt)])], 56 | [with_rgb=$withval], [with_rgb=/etc/X11/rgb.txt]) 57 | AC_DEFINE_UNQUOTED([RGB_FILE], ["$with_rgb"], [Path to rgb.txt file]) 58 | 59 | dnl html widget 60 | AC_ARG_ENABLE([html], 61 | [AS_HELP_STRING([--enable-html], 62 | [Build YAD with HTML widget (default - no)])], 63 | [build_html=$enableval], [build_html=no]) 64 | if test x$build_html = xyes; then 65 | PKG_CHECK_MODULES([HTML], [$WEBKIT], [have_html=yes], [have_html=no]) 66 | if test x$with_gtk = xgtk3; then 67 | if test $have_html = no; then 68 | AC_MSG_WARN([$WEBKIT not found -- not building the HTML widget]) 69 | fi 70 | PKG_CHECK_MODULES([GMODULE], [gmodule-2.0], [have_gmodule=yes], [have_gmodule=no]) 71 | if test $have_gmodule = no; then 72 | AC_MSG_WARN([GModule not found -- not building the HTML widget]) 73 | have_html=no 74 | fi 75 | fi 76 | else 77 | have_html=no 78 | fi 79 | AC_SUBST([HTML_CFLAGS]) 80 | AC_SUBST([HTML_LIBS]) 81 | if test x$build_html = xyes && test x$with_gtk = xgtk3; then 82 | ## because webkitgtk is dynamically loaded 83 | HTML_LIBS= 84 | fi 85 | AM_CONDITIONAL([HTML], [test x$have_html = xyes]) 86 | AC_SUBST([GMODULE_CFLAGS]) 87 | AC_SUBST([GMODULE_LIBS]) 88 | AM_CONDITIONAL([GMODULE], [test x$have_gmodule = xyes]) 89 | 90 | if test x$have_html = xyes; then 91 | AC_DEFINE([HAVE_HTML], [1], [Define this if the webkitgtk library is installed]) 92 | if test x$with_gtk = xgtk3; then 93 | AC_DEFINE_UNQUOTED([WEBKITGTK_LIBNAME], ["lib$WEBKIT.so"], [Define the webkitgtk library file name to be dynamically loaded]) 94 | fi 95 | fi 96 | 97 | dnl gio support 98 | AC_ARG_ENABLE([gio], 99 | [AS_HELP_STRING([--enable-gio], 100 | [Build YAD with GIO support])], 101 | [build_gio=$enableval], [build_gio=yes]) 102 | if test x$build_gio = xyes; then 103 | PKG_CHECK_MODULES([GIO], [gio-2.0], [have_gio=yes], [have_gio=no]) 104 | else 105 | have_gio=no 106 | fi 107 | AC_SUBST([GIO_CFLAGS]) 108 | AC_SUBST([GIO_LIBS]) 109 | 110 | if test x$have_gio = xyes; then 111 | AC_DEFINE([HAVE_GIO], [1], [Define this if you have glib gio framework]) 112 | fi 113 | 114 | dnl status icon widget 115 | AC_ARG_ENABLE([tray], 116 | [AS_HELP_STRING([--enable-tray], 117 | [Build YAD with status icon])], 118 | [build_tray=$enableval], [build_tray=yes]) 119 | AM_CONDITIONAL([TRAY], [test x$build_tray = xyes]) 120 | 121 | if test x$build_tray = xyes; then 122 | AC_DEFINE([HAVE_TRAY], [1], [Define this if you need status icon]) 123 | fi 124 | 125 | dnl spell check 126 | AC_ARG_ENABLE([spell], 127 | [AS_HELP_STRING([--enable-spell], 128 | [Build YAD with Spell check support (default - no)])], 129 | [with_spell=$enableval], [with_spell=no]) 130 | if test x$with_spell = xyes; then 131 | PKG_CHECK_MODULES([SPELL], [$SPELL], [have_spell=yes], [have_spell=no]) 132 | else 133 | have_spell=no 134 | fi 135 | AC_SUBST([SPELL_CFLAGS]) 136 | AC_SUBST([SPELL_LIBS]) 137 | 138 | if test x$have_spell = xyes; then 139 | AC_DEFINE([HAVE_SPELL], [1], [Define this if you need spell check support]) 140 | fi 141 | 142 | dnl sourceview 143 | AC_ARG_ENABLE([sourceview], 144 | [AS_HELP_STRING([--enable-sourceview], 145 | [Build YAD with GtkSourceView support (default - no)])], 146 | [with_sourceview=$enableval], [with_sourceview=no]) 147 | if test x$with_sourceview = xyes; then 148 | PKG_CHECK_MODULES([SOURCEVIEW], [$SOURCEVIEW], [have_sourceview=yes], [have_sourceview=no]) 149 | else 150 | have_sourceview=no 151 | fi 152 | AC_SUBST([SOURCEVIEW_CFLAGS]) 153 | AC_SUBST([SOURCEVIEW_LIBS]) 154 | 155 | if test x$have_sourceview = xyes; then 156 | AC_DEFINE([HAVE_SOURCEVIEW], [1], [Define this if you need GtkSourceView support]) 157 | fi 158 | 159 | dnl tools 160 | AC_ARG_ENABLE([tools], 161 | [AS_HELP_STRING([--enable-tools], 162 | [Build yad-tools utility])], 163 | [build_tools=$enableval], [build_tools=yes]) 164 | AM_CONDITIONAL([BUILD_TOOLS], [test x$build_tools = xyes]) 165 | 166 | dnl icon browser 167 | AC_ARG_ENABLE([icon-browser], 168 | [AS_HELP_STRING([--enable-icon-browser], 169 | [Build YAD icon browser])], 170 | [build_ib=$enableval], [build_ib=yes]) 171 | AM_CONDITIONAL([BUILD_IB], [test x$build_ib = xyes]) 172 | 173 | AC_SEARCH_LIBS(round, m) 174 | 175 | # ******************************* 176 | # Internationalization 177 | # ******************************* 178 | 179 | GETTEXT_PACKAGE=yad 180 | AC_SUBST([GETTEXT_PACKAGE]) 181 | AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext domain]) 182 | 183 | AM_GLIB_GNU_GETTEXT 184 | 185 | # ******************************* 186 | 187 | AC_SUBST([AM_CFLAGS]) 188 | AC_SUBST([AM_CPPFLAGS]) 189 | AC_SUBST([AM_LDFLAGS]) 190 | 191 | # ******************************* 192 | 193 | AC_CONFIG_FILES([ 194 | Makefile 195 | po/Makefile.in 196 | src/Makefile 197 | data/Makefile 198 | data/icons/Makefile 199 | data/icons/16x16/Makefile 200 | data/icons/24x24/Makefile 201 | data/icons/32x32/Makefile 202 | data/icons/48x48/Makefile 203 | data/icons/96x96/Makefile 204 | data/icons/128x128/Makefile 205 | data/yad.m4 206 | data/yad.spec 207 | ]) 208 | 209 | AC_OUTPUT 210 | 211 | echo 212 | echo "Build configuration:" 213 | echo " GTK+ version - $with_gtk" 214 | echo " Path to rgb.txt - $with_rgb" 215 | echo " Status icon - $build_tray" 216 | printf "%s" " HTML widget - $have_html" 217 | if ! test x$have_gmodule = xyes && test x$with_gtk = xgtk3; then 218 | echo " (GModule not found)" 219 | else 220 | echo 221 | fi 222 | echo " Spell checking - $have_spell" 223 | echo " GtkSourceView - $have_sourceview" 224 | echo " GIO support - $have_gio" 225 | echo " Tools - $build_tools" 226 | echo " Icon browser - $build_ib" 227 | echo 228 | -------------------------------------------------------------------------------- /src/cpicker_gtk2.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file is part of YAD. 4 | * 5 | * YAD is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * YAD is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with YAD. If not, see . 17 | * 18 | * Copyright (C) 2023, step https://github.com/step- 19 | */ 20 | 21 | /* Some code adapted from GtkColorSelection widget (gtk/gtkcolorsel.c GTK+-2.24.33) */ 22 | 23 | #define GDK_DISABLE_DEPRECATION_WARNINGS 24 | 25 | #include "cpicker.h" 26 | #include 27 | 28 | #define GDK_BUTTON_PRIMARY (1) 29 | 30 | typedef struct { 31 | GtkWidget *grab_widget; 32 | gboolean has_grab; 33 | guint32 time; 34 | } GrabData; 35 | 36 | static gboolean key_press (GtkWidget * invisible, GdkEventKey * event, gpointer data); 37 | static gboolean mouse_press (GtkWidget * invisible, GdkEventButton * event, gpointer data); 38 | 39 | static GdkCursor * 40 | make_picker_cursor (GdkScreen * screen) 41 | { 42 | GdkDisplay *display; 43 | GdkCursor *cursor; 44 | 45 | display = gdk_screen_get_display (screen); 46 | cursor = gdk_cursor_new_from_name (display, "color-picker"); 47 | if (!cursor) 48 | cursor = gdk_cursor_new_from_name (display, "crosshair"); 49 | if (!cursor) 50 | g_printerr ("cpicker: cannot create cursor\n"); 51 | return cursor; 52 | } 53 | 54 | static void 55 | grab_color_at_pointer (GdkScreen * screen, gint x_root, gint y_root, gpointer data) 56 | { 57 | GdkPixbuf *pixbuf; 58 | guchar *pixels; 59 | GdkColor color; 60 | GdkWindow *root_window = gdk_screen_get_root_window (screen); 61 | GrabData *gd = (GrabData *) data; 62 | 63 | pixbuf = gdk_pixbuf_get_from_drawable (NULL, root_window, NULL, x_root, y_root, 0, 0, 1, 1); 64 | if (!pixbuf) 65 | { 66 | gint x, y; 67 | GdkDisplay *display = gdk_screen_get_display (screen); 68 | GdkWindow *window = gdk_display_get_window_at_pointer (display, &x, &y); 69 | if (!window) 70 | return; 71 | pixbuf = gdk_pixbuf_get_from_drawable (NULL, window, NULL, x, y, 0, 0, 1, 1); 72 | if (!pixbuf) 73 | return; 74 | } 75 | pixels = gdk_pixbuf_get_pixels (pixbuf); 76 | color.red = pixels[0] & 0xFF; 77 | color.green = pixels[1] & 0xFF; 78 | color.blue = pixels[2] & 0xFF; 79 | g_object_unref (pixbuf); 80 | 81 | g_print ("#%02X%02X%02X\n", (gint) color.red, (gint) color.green, (gint) color.blue); 82 | } 83 | 84 | static void 85 | shutdown (gpointer data) 86 | { 87 | GrabData *gd = (GrabData *) data; 88 | 89 | if (gd->has_grab) 90 | { 91 | GdkDisplay *display = gtk_widget_get_display (gd->grab_widget); 92 | gdk_display_keyboard_ungrab (display, gd->time); 93 | gdk_display_pointer_ungrab (display, gd->time); 94 | gtk_grab_remove (gd->grab_widget); 95 | gd->has_grab = FALSE; 96 | } 97 | 98 | gtk_main_quit (); 99 | } 100 | 101 | static void 102 | mouse_motion (GtkWidget * invisible, GdkEventMotion * event, gpointer data) 103 | { 104 | grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event), 105 | event->x_root, event->y_root, data); 106 | } 107 | 108 | static gboolean 109 | mouse_release (GtkWidget * invisible, GdkEventButton * event, gpointer data) 110 | { 111 | /* GrabData *gd = data; */ 112 | 113 | if (event->button != GDK_BUTTON_PRIMARY) 114 | return FALSE; 115 | 116 | grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event), 117 | event->x_root, event->y_root, data); 118 | 119 | shutdown (data); 120 | 121 | g_signal_handlers_disconnect_by_func (invisible, mouse_motion, data); 122 | g_signal_handlers_disconnect_by_func (invisible, mouse_release, data); 123 | 124 | return TRUE; 125 | } 126 | 127 | /* Helper Functions */ 128 | 129 | static gboolean 130 | key_press (GtkWidget * invisible, GdkEventKey * event, gpointer data) 131 | { 132 | GdkDisplay *display = gtk_widget_get_display (invisible); 133 | GdkScreen *screen = gdk_event_get_screen ((GdkEvent *) event); 134 | guint state = event->state & gtk_accelerator_get_default_mod_mask (); 135 | gint x, y, dx, dy; 136 | 137 | gdk_display_get_pointer (display, NULL, &x, &y, NULL); 138 | 139 | dx = dy = 0; 140 | 141 | switch (event->keyval) 142 | { 143 | case GDK_space: 144 | case GDK_Return: 145 | case GDK_ISO_Enter: 146 | case GDK_KP_Enter: 147 | case GDK_KP_Space: 148 | grab_color_at_pointer (screen, x, y, data); 149 | /* fall through */ 150 | 151 | case GDK_Escape: 152 | shutdown (data); 153 | 154 | g_signal_handlers_disconnect_by_func (invisible, mouse_press, data); 155 | g_signal_handlers_disconnect_by_func (invisible, key_press, data); 156 | 157 | return TRUE; 158 | 159 | default: 160 | return FALSE; 161 | } 162 | 163 | gdk_display_warp_pointer (display, screen, x + dx, y + dy); 164 | 165 | return TRUE; 166 | } 167 | 168 | static gboolean 169 | mouse_press (GtkWidget * invisible, GdkEventButton * event, gpointer data) 170 | { 171 | if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) 172 | { 173 | g_signal_connect (invisible, "motion-notify-event", G_CALLBACK (mouse_motion), data); 174 | g_signal_connect (invisible, "button-release-event", G_CALLBACK (mouse_release), data); 175 | g_signal_handlers_disconnect_by_func (invisible, mouse_press, data); 176 | g_signal_handlers_disconnect_by_func (invisible, key_press, data); 177 | return TRUE; 178 | } 179 | 180 | return FALSE; 181 | } 182 | 183 | void 184 | yad_get_screen_color (GtkWidget *widget) 185 | { 186 | GrabData *gd; 187 | GdkScreen *screen; 188 | GdkCursor *picker_cursor; 189 | GdkGrabStatus grab_status; 190 | GdkWindow *window; 191 | 192 | gd = g_new0 (GrabData, 1); 193 | gd->time = GDK_CURRENT_TIME; 194 | 195 | screen = gdk_screen_get_default (); 196 | gd->grab_widget = gtk_window_new (GTK_WINDOW_POPUP); 197 | gtk_window_set_screen (GTK_WINDOW (gd->grab_widget), screen); 198 | gtk_window_resize (GTK_WINDOW (gd->grab_widget), 1, 1); 199 | gtk_window_move (GTK_WINDOW (gd->grab_widget), -100, -100); 200 | gtk_widget_show (gd->grab_widget); 201 | 202 | gtk_widget_add_events (gd->grab_widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); 203 | 204 | window = gtk_widget_get_window (gd->grab_widget); 205 | if (gdk_keyboard_grab (window, 206 | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, gd->time) != GDK_GRAB_SUCCESS) 207 | return; 208 | 209 | picker_cursor = make_picker_cursor (screen); 210 | grab_status = gdk_pointer_grab (window, FALSE, 211 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK, 212 | NULL, picker_cursor, gd->time); 213 | gdk_cursor_unref (picker_cursor); 214 | 215 | if (grab_status != GDK_GRAB_SUCCESS) 216 | { 217 | gdk_keyboard_ungrab (gd->time); 218 | return; 219 | } 220 | 221 | gd->has_grab = TRUE; 222 | 223 | g_signal_connect (gd->grab_widget, "button-press-event", G_CALLBACK (mouse_press), gd); 224 | g_signal_connect (gd->grab_widget, "key-press-event", G_CALLBACK (key_press), gd); 225 | } 226 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include "yad.h" 22 | #include 23 | 24 | enum { 25 | PLUS_BTN = 0, 26 | MINUS_BTN, 27 | }; 28 | 29 | static GtkAdjustment *adj; 30 | static GtkWidget *scale; 31 | static GtkWidget *plus_btn = NULL; 32 | static GtkWidget *minus_btn = NULL; 33 | 34 | static void 35 | value_changed_cb (GtkWidget * w, gpointer data) 36 | { 37 | if (options.scale_data.enforce_step) 38 | { 39 | /* Make sure the new value corresponds to a step in the range. */ 40 | gdouble value = gtk_adjustment_get_value ((GtkAdjustment *)adj); 41 | gdouble new_value = (gdouble) round(value/options.scale_data.step) * options.scale_data.step; 42 | gtk_adjustment_set_value ((GtkAdjustment *)adj, new_value); 43 | } 44 | 45 | if (options.scale_data.print_partial) 46 | g_print ("%.0f\n", gtk_range_get_value (GTK_RANGE (scale))); 47 | 48 | if (options.scale_data.buttons) 49 | { 50 | gdouble v = gtk_range_get_value (GTK_RANGE (scale)); 51 | 52 | if (v >= options.scale_data.max_value) 53 | gtk_widget_set_sensitive (plus_btn, FALSE); 54 | else 55 | gtk_widget_set_sensitive (plus_btn, TRUE); 56 | 57 | if (v <= options.scale_data.min_value) 58 | gtk_widget_set_sensitive (minus_btn, FALSE); 59 | else 60 | gtk_widget_set_sensitive (minus_btn, TRUE); 61 | } 62 | } 63 | 64 | static void 65 | vb_pressed (GtkWidget *b, gpointer data) 66 | { 67 | gdouble v, cv = gtk_range_get_value (GTK_RANGE (scale)); 68 | 69 | switch (GPOINTER_TO_INT (data)) 70 | { 71 | case PLUS_BTN: 72 | v = cv + options.scale_data.step; 73 | gtk_range_set_value (GTK_RANGE (scale), MIN (v, options.scale_data.max_value)); 74 | break; 75 | case MINUS_BTN: 76 | v = cv - options.scale_data.step; 77 | gtk_range_set_value (GTK_RANGE (scale), MAX (v, options.scale_data.min_value)); 78 | break; 79 | } 80 | } 81 | 82 | GtkWidget * 83 | scale_create_widget (GtkWidget * dlg) 84 | { 85 | GtkWidget *w; 86 | gint page; 87 | 88 | if (options.scale_data.min_value >= options.scale_data.max_value) 89 | { 90 | g_printerr (_("Maximum value must be greater than minimum value.\n")); 91 | return NULL; 92 | } 93 | 94 | /* check for initial value */ 95 | if (options.scale_data.have_value) 96 | { 97 | if (options.scale_data.value < options.scale_data.min_value) 98 | { 99 | g_printerr (_("Initial value less than minimal.\n")); 100 | options.scale_data.value = options.scale_data.min_value; 101 | } 102 | else if (options.scale_data.value > options.scale_data.max_value) 103 | { 104 | g_printerr (_("Initial value greater than maximum.\n")); 105 | options.scale_data.value = options.scale_data.max_value; 106 | } 107 | } 108 | else 109 | options.scale_data.value = options.scale_data.min_value; 110 | 111 | page = options.scale_data.page == -1 ? options.scale_data.step * 10 : options.scale_data.page; 112 | /* this type conversion needs only for gtk-2.0 */ 113 | adj = (GtkAdjustment *) gtk_adjustment_new ((double) options.scale_data.value, 114 | (double) options.scale_data.min_value, 115 | (double) options.scale_data.max_value, 116 | (double) options.scale_data.step, 117 | (double) page, 118 | 0.0); 119 | if (options.common_data.vertical) 120 | { 121 | #if GTK_CHECK_VERSION(3,0,0) 122 | scale = gtk_scale_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (adj)); 123 | #else 124 | scale = gtk_vscale_new (GTK_ADJUSTMENT (adj)); 125 | #endif 126 | gtk_range_set_inverted (GTK_RANGE (scale), !options.scale_data.invert); 127 | } 128 | else 129 | { 130 | #if GTK_CHECK_VERSION(3,0,0) 131 | scale = gtk_scale_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (adj)); 132 | #else 133 | scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); 134 | #endif 135 | gtk_range_set_inverted (GTK_RANGE (scale), options.scale_data.invert); 136 | } 137 | gtk_widget_set_name (scale, "yad-scale-widget"); 138 | gtk_scale_set_digits (GTK_SCALE (scale), 0); 139 | 140 | if (options.scale_data.hide_value) 141 | gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE); 142 | 143 | /* add marks */ 144 | if (options.scale_data.marks) 145 | { 146 | GtkPositionType pos; 147 | GSList *m = options.scale_data.marks; 148 | 149 | pos = options.common_data.vertical ? GTK_POS_LEFT : GTK_POS_BOTTOM; 150 | for (; m; m = m->next) 151 | { 152 | YadScaleMark *mark = (YadScaleMark *) m->data; 153 | gtk_scale_add_mark (GTK_SCALE (scale), mark->value, pos, mark->name); 154 | } 155 | } 156 | 157 | /* create container */ 158 | if (options.common_data.vertical) 159 | { 160 | #if GTK_CHECK_VERSION(3,0,0) 161 | w = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1); 162 | #else 163 | w = gtk_vbox_new (FALSE, 1); 164 | #endif 165 | } 166 | else 167 | { 168 | #if GTK_CHECK_VERSION(3,0,0) 169 | w = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 1); 170 | #else 171 | w = gtk_hbox_new (FALSE, 1); 172 | #endif 173 | } 174 | 175 | /* create buttons */ 176 | if (options.scale_data.buttons) 177 | { 178 | minus_btn = gtk_button_new_with_label ("-"); 179 | gtk_button_set_relief (GTK_BUTTON (minus_btn), GTK_RELIEF_NONE); 180 | g_signal_connect (G_OBJECT (minus_btn), "clicked", G_CALLBACK (vb_pressed), GINT_TO_POINTER (MINUS_BTN)); 181 | gtk_widget_set_sensitive (minus_btn, (options.scale_data.value > options.scale_data.min_value)); 182 | 183 | plus_btn = gtk_button_new_with_label ("+"); 184 | gtk_button_set_relief (GTK_BUTTON (plus_btn), GTK_RELIEF_NONE); 185 | g_signal_connect (G_OBJECT (plus_btn), "clicked", G_CALLBACK (vb_pressed), GINT_TO_POINTER (PLUS_BTN)); 186 | gtk_widget_set_sensitive (plus_btn, (options.scale_data.value < options.scale_data.max_value)); 187 | } 188 | 189 | /* create complex widget */ 190 | if (options.scale_data.buttons) 191 | gtk_box_pack_start (GTK_BOX (w), options.common_data.vertical ? plus_btn : minus_btn, FALSE, FALSE, 0); 192 | 193 | gtk_box_pack_start (GTK_BOX (w), scale, TRUE, TRUE, 2); 194 | 195 | if (options.scale_data.buttons) 196 | gtk_box_pack_start (GTK_BOX (w), options.common_data.vertical ? minus_btn : plus_btn, FALSE, FALSE, 0); 197 | 198 | g_signal_connect (G_OBJECT (scale), "value-changed", G_CALLBACK (value_changed_cb), NULL); 199 | gtk_widget_grab_focus (scale); 200 | 201 | return w; 202 | } 203 | 204 | void 205 | scale_print_result (void) 206 | { 207 | g_print ("%.0f\n", gtk_range_get_value (GTK_RANGE (scale))); 208 | } 209 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | 23 | #include "yad.h" 24 | #if GTK_CHECK_VERSION(3,0,0) 25 | #include "cpicker.h" 26 | #endif 27 | 28 | static GtkWidget *color; 29 | 30 | static GtkTreeModel * 31 | create_palette () 32 | { 33 | FILE *fp; 34 | gchar *filename; 35 | gchar buf[1024], *name; 36 | GtkListStore *store; 37 | GdkPixbuf *pb; 38 | GtkTreeIter iter; 39 | 40 | gchar *cxpm[] = { 41 | "16 14 1 1", 42 | ". c #FFFFFF", 43 | "................", 44 | "................", 45 | "................", 46 | "................", 47 | "................", 48 | "................", 49 | "................", 50 | "................", 51 | "................", 52 | "................", 53 | "................", 54 | "................", 55 | "................", 56 | "................" 57 | }; 58 | gchar cl[] = ". c #FFFFFF"; 59 | 60 | if (options.color_data.palette) 61 | filename = options.color_data.palette; 62 | else 63 | filename = RGB_FILE; 64 | 65 | if ((fp = fopen (filename, "r")) == NULL) 66 | { 67 | g_printerr (_("Can't open file %s: %s\n"), filename, strerror (errno)); 68 | return NULL; 69 | } 70 | 71 | store = gtk_list_store_new (3, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING); 72 | 73 | while ((name = fgets (buf, sizeof (buf), fp)) != NULL) 74 | { 75 | gint r, g, b; 76 | gchar spec[8]; 77 | 78 | if (buf[0] == '!') 79 | continue; 80 | 81 | sscanf (buf, "%d %d %d", &r, &g, &b); 82 | 83 | g_sprintf (spec, "#%.2X%.2X%.2X", r, g, b); 84 | g_sprintf (cl, ". c #%.2X%.2X%.2X", r, g, b); 85 | cxpm[1] = cl; 86 | pb = gdk_pixbuf_new_from_xpm_data ((const gchar **) cxpm); 87 | 88 | while (g_ascii_isdigit (*name) || g_ascii_isspace (*name)) 89 | name++; 90 | 91 | gtk_list_store_append (store, &iter); 92 | gtk_list_store_set (store, &iter, 0, pb, 1, spec, 2, g_strstrip (name), -1); 93 | } 94 | 95 | fclose (fp); 96 | 97 | return GTK_TREE_MODEL (store); 98 | } 99 | 100 | static void 101 | set_color (gchar *clr) 102 | { 103 | #if !GTK_CHECK_VERSION(3,4,0) 104 | GdkColor c; 105 | if (gdk_color_parse (clr, &c)) 106 | gtk_color_selection_set_current_color (GTK_COLOR_SELECTION (color), &c); 107 | #else 108 | GdkRGBA c; 109 | if (gdk_rgba_parse (&c, clr)) 110 | gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color), &c); 111 | #endif 112 | } 113 | 114 | #if GTK_CHECK_VERSION(3,0,0) 115 | static void 116 | picker_clicked (GtkWidget *w, gpointer data) 117 | { 118 | yad_get_screen_color (color); 119 | } 120 | #endif 121 | 122 | static void 123 | palette_changed (GtkTreeSelection * sel, gpointer data) 124 | { 125 | GtkTreeModel *model; 126 | GtkTreeIter iter; 127 | 128 | if (gtk_tree_selection_get_selected (sel, &model, &iter)) 129 | { 130 | gchar *clr; 131 | gtk_tree_model_get (model, &iter, 1, &clr, -1); 132 | set_color (clr); 133 | } 134 | } 135 | 136 | GtkWidget * 137 | color_create_widget (GtkWidget * dlg) 138 | { 139 | GtkWidget *w; 140 | 141 | #if !GTK_CHECK_VERSION(3,4,0) 142 | w = gtk_vbox_new (FALSE, 2); 143 | color = gtk_color_selection_new (); 144 | #else 145 | w = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2); 146 | color = gtk_color_chooser_widget_new (); 147 | #endif 148 | 149 | gtk_widget_set_name (color, "yad-color-widget"); 150 | #if !GTK_CHECK_VERSION(3,4,0) 151 | gtk_color_selection_set_has_palette (GTK_COLOR_SELECTION (color), options.color_data.gtk_palette); 152 | #else 153 | g_object_set (G_OBJECT (color), "show-editor", !options.color_data.gtk_palette, NULL); 154 | #endif 155 | if (options.color_data.init_color) 156 | set_color (options.color_data.init_color); 157 | gtk_box_pack_start (GTK_BOX (w), color, FALSE, FALSE, 2); 158 | 159 | #if GTK_CHECK_VERSION(3,0,0) 160 | if (options.color_data.color_picker) 161 | { 162 | GtkWidget *b, *i; 163 | 164 | b = gtk_button_new_with_label (_("Pick screen color")); 165 | 166 | i = gtk_image_new_from_icon_name ("gtk-color-picker", GTK_ICON_SIZE_BUTTON); 167 | gtk_button_set_image (GTK_BUTTON (b), i); 168 | g_object_set (G_OBJECT (b), "always-show-image", TRUE, NULL); 169 | 170 | g_signal_connect (G_OBJECT (b), "clicked", G_CALLBACK (picker_clicked), NULL); 171 | 172 | gtk_box_pack_start (GTK_BOX (w), b, FALSE, FALSE, 2); 173 | } 174 | #endif 175 | 176 | if (options.color_data.use_palette) 177 | { 178 | GtkTreeModel *model; 179 | 180 | if ((model = create_palette ()) != NULL) 181 | { 182 | GtkWidget *exp, *sw, *list; 183 | GtkCellRenderer *r; 184 | GtkTreeViewColumn *col; 185 | GtkTreeSelection *sel; 186 | 187 | /* create expander */ 188 | exp = gtk_expander_new (_("Palette")); 189 | gtk_expander_set_expanded (GTK_EXPANDER (exp), options.color_data.expand_palette); 190 | gtk_container_set_border_width (GTK_CONTAINER (exp), 5); 191 | gtk_box_pack_start (GTK_BOX (w), exp, TRUE, TRUE, 2); 192 | 193 | /* create color list */ 194 | sw = gtk_scrolled_window_new (NULL, NULL); 195 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); 196 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.data.hscroll_policy, options.data.vscroll_policy); 197 | gtk_widget_set_size_request (sw, -1, 75); 198 | gtk_container_add (GTK_CONTAINER (exp), sw); 199 | #if GTK_CHECK_VERSION(3,0,0) 200 | gtk_widget_set_vexpand (sw, TRUE); 201 | #endif 202 | list = gtk_tree_view_new_with_model (model); 203 | gtk_widget_set_name (list, "yad-color-palette"); 204 | g_object_unref (model); 205 | gtk_container_add (GTK_CONTAINER (sw), list); 206 | 207 | /* add first columns */ 208 | col = gtk_tree_view_column_new (); 209 | gtk_tree_view_column_set_title (col, _("Color")); 210 | 211 | /* pixbuf */ 212 | r = gtk_cell_renderer_pixbuf_new (); 213 | gtk_tree_view_column_pack_start (col, r, FALSE); 214 | gtk_tree_view_column_set_attributes (col, r, "pixbuf", 0, NULL); 215 | 216 | /* color value */ 217 | r = gtk_cell_renderer_text_new (); 218 | gtk_tree_view_column_pack_start (col, r, TRUE); 219 | gtk_tree_view_column_set_attributes (col, r, "text", 1, NULL); 220 | 221 | gtk_tree_view_column_set_sort_column_id (col, 1); 222 | gtk_tree_view_append_column (GTK_TREE_VIEW (list), col); 223 | 224 | /* add second column */ 225 | r = gtk_cell_renderer_text_new (); 226 | col = gtk_tree_view_column_new_with_attributes (_("Name"), r, "text", 2, NULL); 227 | gtk_tree_view_column_set_sort_column_id (col, 2); 228 | gtk_tree_view_append_column (GTK_TREE_VIEW (list), col); 229 | 230 | /* enable searching on Name column */ 231 | gtk_tree_view_set_search_column (GTK_TREE_VIEW (list), 2); 232 | 233 | /* setup the selection handler */ 234 | sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (list)); 235 | gtk_tree_selection_set_mode (sel, GTK_SELECTION_SINGLE); 236 | g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (palette_changed), NULL); 237 | 238 | gtk_widget_show_all (exp); 239 | } 240 | } 241 | 242 | return w; 243 | } 244 | 245 | void 246 | color_print_result (void) 247 | { 248 | #if !GTK_CHECK_VERSION(3,4,0) 249 | GdkColor c; 250 | guint64 alpha; 251 | #else 252 | GdkRGBA c; 253 | #endif 254 | gchar *cs; 255 | 256 | #if !GTK_CHECK_VERSION(3,4,0) 257 | gtk_color_selection_get_current_color (GTK_COLOR_SELECTION (color), &c); 258 | alpha = gtk_color_selection_get_current_alpha (GTK_COLOR_SELECTION (color)); 259 | cs = get_color (&c, alpha); 260 | #else 261 | gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (color), &c); 262 | cs = get_color (&c); 263 | #endif 264 | 265 | if (cs) 266 | g_printf ("%s\n", cs); 267 | } 268 | -------------------------------------------------------------------------------- /src/picture.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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include "yad.h" 22 | 23 | static GtkWidget *picture; 24 | static GtkWidget *viewport; 25 | static GtkWidget *popup_menu; 26 | 27 | static GdkPixbufAnimation *anim_pb; 28 | static GdkPixbuf *orig_pb; 29 | 30 | static gboolean loaded = FALSE; 31 | static gboolean animated = FALSE; 32 | 33 | enum { 34 | SIZE_FIT, 35 | SIZE_ORIG, 36 | SIZE_INC, 37 | SIZE_DEC 38 | }; 39 | 40 | enum { 41 | ROTATE_LEFT, 42 | ROTATE_RIGHT, 43 | ROTATE_FLIP_VERT, 44 | ROTATE_FLIP_HOR 45 | }; 46 | 47 | static void 48 | load_picture (gchar *filename) 49 | { 50 | anim_pb = gdk_pixbuf_animation_new_from_file (filename, NULL); 51 | orig_pb = gdk_pixbuf_animation_get_static_image (anim_pb); 52 | 53 | if (orig_pb) 54 | { 55 | if (gdk_pixbuf_animation_is_static_image (anim_pb)) 56 | gtk_image_set_from_pixbuf (GTK_IMAGE (picture), orig_pb); 57 | else 58 | { 59 | gtk_image_set_from_animation (GTK_IMAGE (picture), anim_pb); 60 | animated = TRUE; 61 | } 62 | loaded = TRUE; 63 | } 64 | else 65 | gtk_image_set_from_icon_name (GTK_IMAGE (picture), "image-missing", GTK_ICON_SIZE_DIALOG); 66 | } 67 | 68 | void 69 | picture_fit_to_window () 70 | { 71 | gdouble width, height, ww, wh; 72 | gdouble factor; 73 | 74 | if (animated) 75 | return; 76 | 77 | width = gdk_pixbuf_get_width (orig_pb); 78 | height = gdk_pixbuf_get_height (orig_pb); 79 | 80 | ww = gdk_window_get_width (gtk_viewport_get_view_window (GTK_VIEWPORT (viewport))); 81 | wh = gdk_window_get_height (gtk_viewport_get_view_window (GTK_VIEWPORT (viewport))); 82 | 83 | factor = MIN (ww / width, wh / height); 84 | if (factor < 1.0) 85 | { 86 | GdkPixbuf *pb = gdk_pixbuf_scale_simple (g_object_ref (orig_pb), width * factor, height * factor, GDK_INTERP_HYPER); 87 | if (pb) 88 | { 89 | GdkPixbuf *old_pb = gtk_image_get_pixbuf (GTK_IMAGE (picture)); 90 | gtk_image_set_from_pixbuf (GTK_IMAGE (picture), pb); 91 | g_object_unref (old_pb); 92 | } 93 | } 94 | } 95 | 96 | static void 97 | change_size_cb (GtkWidget *w, gint type) 98 | { 99 | gdouble width, height; 100 | GdkPixbuf *new_pb, *pb = gtk_image_get_pixbuf (GTK_IMAGE (picture)); 101 | 102 | if (!pb) 103 | { 104 | g_printerr ("picture: can't get pixbuf\n"); 105 | return; 106 | } 107 | 108 | width = gdk_pixbuf_get_width (pb); 109 | height = gdk_pixbuf_get_height (pb); 110 | 111 | switch (type) 112 | { 113 | case SIZE_FIT: 114 | picture_fit_to_window (); 115 | break; 116 | case SIZE_ORIG: 117 | gtk_image_set_from_pixbuf (GTK_IMAGE (picture), orig_pb); 118 | g_object_unref (pb); 119 | break; 120 | case SIZE_INC: 121 | new_pb = gdk_pixbuf_scale_simple (pb, width + options.picture_data.inc, 122 | height + options.picture_data.inc, GDK_INTERP_HYPER); 123 | if (new_pb) 124 | { 125 | gtk_image_set_from_pixbuf (GTK_IMAGE (picture), new_pb); 126 | g_object_unref (pb); 127 | } 128 | break; 129 | case SIZE_DEC: 130 | new_pb = gdk_pixbuf_scale_simple (pb, width - options.picture_data.inc, 131 | height - options.picture_data.inc, GDK_INTERP_HYPER); 132 | if (new_pb) 133 | { 134 | gtk_image_set_from_pixbuf (GTK_IMAGE (picture), new_pb); 135 | g_object_unref (pb); 136 | } 137 | break; 138 | } 139 | } 140 | 141 | static void 142 | rotate_cb (GtkWidget *w, gint type) 143 | { 144 | GdkPixbuf *new_pb = NULL; 145 | GdkPixbuf *pb = gtk_image_get_pixbuf (GTK_IMAGE (picture)); 146 | 147 | if (!pb) 148 | { 149 | g_printerr ("picture: can't get pixbuf\n"); 150 | return; 151 | } 152 | 153 | switch (type) 154 | { 155 | case ROTATE_LEFT: 156 | new_pb = gdk_pixbuf_rotate_simple (pb, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE); 157 | break; 158 | case ROTATE_RIGHT: 159 | new_pb = gdk_pixbuf_rotate_simple (pb, GDK_PIXBUF_ROTATE_CLOCKWISE); 160 | break; 161 | case ROTATE_FLIP_VERT: 162 | new_pb = gdk_pixbuf_flip (pb, FALSE); 163 | break; 164 | case ROTATE_FLIP_HOR: 165 | new_pb = gdk_pixbuf_flip (pb, TRUE); 166 | break; 167 | } 168 | 169 | if (new_pb) 170 | { 171 | gtk_image_set_from_pixbuf (GTK_IMAGE (picture), new_pb); 172 | g_object_unref (pb); 173 | } 174 | } 175 | 176 | static void 177 | create_popup_menu () 178 | { 179 | GtkWidget *mi; 180 | 181 | popup_menu = gtk_menu_new (); 182 | gtk_menu_set_reserve_toggle_size (GTK_MENU (popup_menu), FALSE); 183 | 184 | mi = gtk_menu_item_new_with_label (_("Fit to window")); 185 | gtk_widget_show (mi); 186 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 187 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (change_size_cb), GINT_TO_POINTER (SIZE_FIT)); 188 | 189 | mi = gtk_menu_item_new_with_label (_("Original size")); 190 | gtk_widget_show (mi); 191 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 192 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (change_size_cb), GINT_TO_POINTER (SIZE_ORIG)); 193 | 194 | mi = gtk_menu_item_new_with_label (_("Increase size")); 195 | gtk_widget_show (mi); 196 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 197 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (change_size_cb), GINT_TO_POINTER (SIZE_INC)); 198 | 199 | mi = gtk_menu_item_new_with_label (_("Decrease size")); 200 | gtk_widget_show (mi); 201 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 202 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (change_size_cb), GINT_TO_POINTER (SIZE_DEC)); 203 | 204 | mi = gtk_separator_menu_item_new (); 205 | gtk_widget_show (mi); 206 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 207 | 208 | mi = gtk_menu_item_new_with_label (_("Rotate left")); 209 | gtk_widget_show (mi); 210 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 211 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (rotate_cb), GINT_TO_POINTER (ROTATE_LEFT)); 212 | 213 | mi = gtk_menu_item_new_with_label (_("Rotate right")); 214 | gtk_widget_show (mi); 215 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 216 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (rotate_cb), GINT_TO_POINTER (ROTATE_RIGHT)); 217 | 218 | mi = gtk_menu_item_new_with_label (_("Flip vertical")); 219 | gtk_widget_show (mi); 220 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 221 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (rotate_cb), GINT_TO_POINTER (ROTATE_FLIP_VERT)); 222 | 223 | mi = gtk_menu_item_new_with_label (_("Flip horizontal")); 224 | gtk_widget_show (mi); 225 | gtk_menu_shell_append (GTK_MENU_SHELL (popup_menu), mi); 226 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (rotate_cb), GINT_TO_POINTER (ROTATE_FLIP_HOR)); 227 | } 228 | 229 | static gboolean 230 | button_handler (GtkWidget *w, GdkEventButton *ev, gpointer data) 231 | { 232 | if (ev->button == 3) 233 | { 234 | #if GTK_CHECK_VERSION(3,22,0) 235 | gtk_menu_popup_at_pointer (GTK_MENU (popup_menu), NULL); 236 | #else 237 | gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL, NULL, NULL, ev->button, ev->time); 238 | #endif 239 | return TRUE; 240 | } 241 | 242 | return FALSE; 243 | } 244 | 245 | static gboolean 246 | key_handler (GtkWidget *w, GdkEventKey *ev, gpointer data) 247 | { 248 | return FALSE; 249 | } 250 | 251 | GtkWidget * 252 | picture_create_widget (GtkWidget * dlg) 253 | { 254 | GtkWidget *sw, *ev; 255 | 256 | sw = gtk_scrolled_window_new (NULL, NULL); 257 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE); 258 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.data.hscroll_policy, options.data.vscroll_policy); 259 | 260 | viewport = gtk_viewport_new (gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (sw)), 261 | gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw))); 262 | gtk_container_add (GTK_CONTAINER (sw), viewport); 263 | 264 | ev = gtk_event_box_new (); 265 | gtk_container_add (GTK_CONTAINER (viewport), ev); 266 | 267 | picture = gtk_image_new (); 268 | gtk_container_add (GTK_CONTAINER (ev), picture); 269 | 270 | /* load picture */ 271 | if (options.common_data.uri && 272 | g_file_test (options.common_data.uri, G_FILE_TEST_EXISTS)) 273 | load_picture (options.common_data.uri); 274 | else 275 | gtk_image_set_from_icon_name (GTK_IMAGE (picture), "image-missing", GTK_ICON_SIZE_DIALOG); 276 | 277 | if (loaded && !animated) 278 | { 279 | create_popup_menu (); 280 | g_signal_connect (G_OBJECT (ev), "button-press-event", G_CALLBACK (button_handler), NULL); 281 | g_signal_connect (G_OBJECT (ev), "key-press-event", G_CALLBACK (key_handler), NULL); 282 | } 283 | 284 | return sw; 285 | } 286 | -------------------------------------------------------------------------------- /src/cpicker.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * This file is part of YAD. 4 | * 5 | * YAD is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * YAD is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with YAD. If not, see . 17 | * 18 | * Copyright (C) 2020-2022, Victor Ananjevsky 19 | * Copyright (C) 2019-2025, step https://github.com/step- 20 | */ 21 | 22 | /* This code getted from deprecated GtkColorSelection widget (gtk+-3.24.33) */ 23 | 24 | #define GDK_DISABLE_DEPRECATION_WARNINGS 25 | 26 | #include "cpicker.h" 27 | 28 | #define BIG_STEP 20 29 | 30 | typedef struct { 31 | GtkWidget *color_widget; 32 | GtkWidget *grab_widget; 33 | GdkDevice *keyb_device; 34 | GdkDevice *pointer_device; 35 | gboolean has_grab; 36 | guint32 time; 37 | } GrabData; 38 | 39 | static GdkRGBA selected_color; /* selected color */ 40 | static gboolean pickup_made = FALSE; /* true when color was picked up */ 41 | static gboolean pickup_done = FALSE; /* true when pickup was made or canceled */ 42 | 43 | static gboolean key_press (GtkWidget * invisible, GdkEventKey * event, gpointer data); 44 | static gboolean mouse_press (GtkWidget * invisible, GdkEventButton * event, gpointer data); 45 | 46 | static GdkCursor * 47 | make_picker_cursor (GdkScreen * screen) 48 | { 49 | GdkDisplay *display; 50 | GdkCursor *cursor; 51 | 52 | display = gdk_screen_get_display (screen); 53 | cursor = gdk_cursor_new_from_name (display, "color-picker"); 54 | if (!cursor) 55 | cursor = gdk_cursor_new_from_name (display, "cell"); 56 | if (!cursor) 57 | g_printerr ("cpicker: cannot create cursor\n"); 58 | return cursor; 59 | } 60 | 61 | static void 62 | grab_color_at_pointer (GdkScreen * screen, GdkDevice * device, gint x_root, gint y_root, gpointer data) 63 | { 64 | GdkPixbuf *pixbuf; 65 | guchar *pixels; 66 | GdkRGBA color; 67 | GdkWindow *root_window = gdk_screen_get_root_window (screen); 68 | GrabData *gd = (GrabData *) data; 69 | 70 | pixbuf = gdk_pixbuf_get_from_window (root_window, x_root, y_root, 1, 1); 71 | if (!pixbuf) 72 | { 73 | gint x, y; 74 | GdkWindow *window = gdk_device_get_window_at_position (device, &x, &y); 75 | if (!window) 76 | return; 77 | pixbuf = gdk_pixbuf_get_from_window (window, x, y, 1, 1); 78 | if (!pixbuf) 79 | return; 80 | } 81 | pixels = gdk_pixbuf_get_pixels (pixbuf); 82 | color.red = pixels[0] / 255.; 83 | color.green = pixels[1] / 255.; 84 | color.blue = pixels[2] / 255.; 85 | color.alpha = 1.0; 86 | g_object_unref (pixbuf); 87 | 88 | if (gd->color_widget) 89 | gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (gd->color_widget), &color); 90 | else 91 | g_print ("#%02X%02X%02X\n", (gint) (color.red * 255), (gint) (color.green * 255), (gint) (color.blue * 255)); 92 | } 93 | 94 | static void 95 | shutdown_eyedropper (gpointer data) 96 | { 97 | GrabData *gd = (GrabData *) data; 98 | 99 | if (gd->has_grab) 100 | { 101 | gdk_device_ungrab (gd->keyb_device, gd->time); 102 | gdk_device_ungrab (gd->pointer_device, gd->time); 103 | gtk_device_grab_remove (gd->grab_widget, gd->pointer_device); 104 | } 105 | 106 | if (gd->color_widget == NULL) 107 | gtk_main_quit (); 108 | } 109 | 110 | static void 111 | mouse_motion (GtkWidget * invisible, GdkEventMotion * event, gpointer data) 112 | { 113 | grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event), 114 | gdk_event_get_device ((GdkEvent *) event), event->x_root, event->y_root, data); 115 | } 116 | 117 | static gboolean 118 | mouse_release (GtkWidget * invisible, GdkEventButton * event, gpointer data) 119 | { 120 | /* GtkColorSelection *colorsel = data; */ 121 | 122 | if (event->button != GDK_BUTTON_PRIMARY) 123 | return FALSE; 124 | 125 | grab_color_at_pointer (gdk_event_get_screen ((GdkEvent *) event), 126 | gdk_event_get_device ((GdkEvent *) event), event->x_root, event->y_root, data); 127 | 128 | shutdown_eyedropper (data); 129 | 130 | g_signal_handlers_disconnect_by_func (invisible, mouse_motion, data); 131 | g_signal_handlers_disconnect_by_func (invisible, mouse_release, data); 132 | 133 | return TRUE; 134 | } 135 | 136 | /* Helper Functions */ 137 | 138 | static gboolean 139 | key_press (GtkWidget * invisible, GdkEventKey * event, gpointer data) 140 | { 141 | GdkScreen *screen = gdk_event_get_screen ((GdkEvent *) event); 142 | GdkDevice *device, *pointer_device; 143 | guint state = event->state & gtk_accelerator_get_default_mod_mask (); 144 | gint x, y, dx, dy; 145 | 146 | device = gdk_event_get_device ((GdkEvent *) event); 147 | pointer_device = gdk_device_get_associated_device (device); 148 | gdk_device_get_position (pointer_device, NULL, &x, &y); 149 | 150 | dx = dy = 0; 151 | 152 | switch (event->keyval) 153 | { 154 | case GDK_KEY_space: 155 | case GDK_KEY_Return: 156 | case GDK_KEY_ISO_Enter: 157 | case GDK_KEY_KP_Enter: 158 | case GDK_KEY_KP_Space: 159 | grab_color_at_pointer (screen, pointer_device, x, y, data); 160 | /* fall through */ 161 | 162 | case GDK_KEY_Escape: 163 | shutdown_eyedropper (data); 164 | 165 | g_signal_handlers_disconnect_by_func (invisible, mouse_press, data); 166 | g_signal_handlers_disconnect_by_func (invisible, key_press, data); 167 | 168 | return TRUE; 169 | 170 | case GDK_KEY_Up: 171 | case GDK_KEY_KP_Up: 172 | dy = state == GDK_MOD1_MASK ? -BIG_STEP : -1; 173 | break; 174 | 175 | case GDK_KEY_Down: 176 | case GDK_KEY_KP_Down: 177 | dy = state == GDK_MOD1_MASK ? BIG_STEP : 1; 178 | break; 179 | 180 | case GDK_KEY_Left: 181 | case GDK_KEY_KP_Left: 182 | dx = state == GDK_MOD1_MASK ? -BIG_STEP : -1; 183 | break; 184 | 185 | case GDK_KEY_Right: 186 | case GDK_KEY_KP_Right: 187 | dx = state == GDK_MOD1_MASK ? BIG_STEP : 1; 188 | break; 189 | 190 | default: 191 | return FALSE; 192 | } 193 | 194 | gdk_device_warp (pointer_device, screen, x + dx, y + dy); 195 | 196 | return TRUE; 197 | } 198 | 199 | static gboolean 200 | mouse_press (GtkWidget * invisible, GdkEventButton * event, gpointer data) 201 | { 202 | if (event->type == GDK_BUTTON_PRESS && event->button == GDK_BUTTON_PRIMARY) 203 | { 204 | g_signal_connect (invisible, "motion-notify-event", G_CALLBACK (mouse_motion), data); 205 | g_signal_connect (invisible, "button-release-event", G_CALLBACK (mouse_release), data); 206 | g_signal_handlers_disconnect_by_func (invisible, mouse_press, data); 207 | g_signal_handlers_disconnect_by_func (invisible, key_press, data); 208 | return TRUE; 209 | } 210 | 211 | return FALSE; 212 | } 213 | 214 | void 215 | yad_get_screen_color (GtkWidget *widget) 216 | { 217 | GrabData *gd; 218 | GdkScreen *screen; 219 | GdkDevice *device; 220 | GdkCursor *picker_cursor; 221 | GdkGrabStatus grab_status; 222 | GdkWindow *window; 223 | 224 | gd = g_new0 (GrabData, 1); 225 | gd->color_widget = widget; 226 | gd->time = gtk_get_current_event_time (); 227 | 228 | screen = gdk_screen_get_default (); 229 | device = gtk_get_current_event_device (); 230 | 231 | if (device) 232 | { 233 | if (gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD) 234 | { 235 | gd->keyb_device = device; 236 | gd->pointer_device = gdk_device_get_associated_device (device); 237 | } 238 | else 239 | { 240 | gd->pointer_device = device; 241 | gd->keyb_device = gdk_device_get_associated_device (device); 242 | } 243 | } 244 | else 245 | { 246 | GdkSeat *seat = gdk_display_get_default_seat (gdk_screen_get_display (screen)); 247 | gd->keyb_device = gdk_seat_get_keyboard (seat); 248 | gd->pointer_device = gdk_seat_get_pointer (seat); 249 | } 250 | 251 | gd->grab_widget = gtk_window_new (GTK_WINDOW_POPUP); 252 | gtk_window_set_screen (GTK_WINDOW (gd->grab_widget), screen); 253 | gtk_window_resize (GTK_WINDOW (gd->grab_widget), 1, 1); 254 | gtk_window_move (GTK_WINDOW (gd->grab_widget), -100, -100); 255 | gtk_widget_show (gd->grab_widget); 256 | 257 | gtk_widget_add_events (gd->grab_widget, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK); 258 | 259 | window = gtk_widget_get_window (gd->grab_widget); 260 | if (gdk_device_grab (gd->keyb_device, window, GDK_OWNERSHIP_APPLICATION, FALSE, 261 | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, gd->time) != GDK_GRAB_SUCCESS) 262 | return; 263 | 264 | picker_cursor = make_picker_cursor (screen); 265 | grab_status = gdk_device_grab (gd->pointer_device, window, GDK_OWNERSHIP_APPLICATION, FALSE, 266 | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK, 267 | picker_cursor, gd->time); 268 | if (picker_cursor) 269 | g_object_unref (picker_cursor); 270 | 271 | if (grab_status != GDK_GRAB_SUCCESS) 272 | { 273 | gdk_device_ungrab (gd->keyb_device, gd->time); 274 | return; 275 | } 276 | 277 | gtk_device_grab_add (gd->grab_widget, gd->pointer_device, TRUE); 278 | 279 | gd->has_grab = TRUE; 280 | 281 | g_signal_connect (gd->grab_widget, "button-press-event", G_CALLBACK (mouse_press), gd); 282 | g_signal_connect (gd->grab_widget, "key-press-event", G_CALLBACK (key_press), gd); 283 | } 284 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include "yad.h" 22 | 23 | static GtkWidget *entry; 24 | static gboolean is_combo = FALSE; 25 | 26 | static void 27 | entry_activate_cb (GtkEntry * entry, gpointer data) 28 | { 29 | if (options.plug == -1) 30 | yad_exit (options.data.def_resp); 31 | } 32 | 33 | static gboolean 34 | combo_activate_cb (GtkWidget * w, GdkEventKey * ev, gpointer data) 35 | { 36 | if (ev->keyval == GDK_KEY_Return || ev->keyval == GDK_KEY_KP_Enter) 37 | { 38 | if (options.plug == -1) 39 | yad_exit (options.data.def_resp); 40 | return TRUE; 41 | } 42 | return FALSE; 43 | } 44 | 45 | static void 46 | icon_cb (GtkEntry * entry, GtkEntryIconPosition pos, GdkEventButton * event, gpointer data) 47 | { 48 | if (event->button == 1) 49 | { 50 | gchar *cmd = NULL; 51 | 52 | switch (pos) 53 | { 54 | case GTK_ENTRY_ICON_PRIMARY: 55 | cmd = options.entry_data.licon_action; 56 | break; 57 | case GTK_ENTRY_ICON_SECONDARY: 58 | cmd = options.entry_data.ricon_action; 59 | break; 60 | } 61 | 62 | if (cmd) 63 | { 64 | FILE *pf; 65 | gchar buf[1024]; 66 | GString *str; 67 | 68 | str = g_string_new (""); 69 | pf = popen (cmd, "r"); 70 | while (fgets (buf, sizeof (buf), pf)) 71 | g_string_append (str, buf); 72 | if (pclose (pf) == 0) 73 | { 74 | if (str->str[str->len - 1] == '\n') 75 | str->str[str->len - 1] = '\0'; 76 | gtk_entry_set_text (GTK_ENTRY (entry), str->str); 77 | } 78 | g_string_free (str, TRUE); 79 | } 80 | else 81 | gtk_entry_set_text (GTK_ENTRY (entry), ""); 82 | 83 | /* move cursor to the end of text */ 84 | gtk_editable_set_position (GTK_EDITABLE (entry), -1); 85 | } 86 | } 87 | 88 | static GtkTreeModel * 89 | create_completion_model (void) 90 | { 91 | GtkListStore *store; 92 | GtkTreeIter iter; 93 | gint i = 0; 94 | 95 | store = gtk_list_store_new (1, G_TYPE_STRING); 96 | 97 | if (options.extra_data) 98 | { 99 | while (options.extra_data[i] != NULL) 100 | { 101 | gtk_list_store_append (store, &iter); 102 | gtk_list_store_set (store, &iter, 0, options.extra_data[i], -1); 103 | i++; 104 | } 105 | } 106 | 107 | return GTK_TREE_MODEL (store); 108 | } 109 | 110 | GtkWidget * 111 | entry_create_widget (GtkWidget * dlg) 112 | { 113 | GtkWidget *c, *l = NULL, *w = NULL; 114 | 115 | #if !GTK_CHECK_VERSION(3,0,0) 116 | w = gtk_hbox_new (FALSE, 5); 117 | #else 118 | w = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); 119 | #endif 120 | 121 | if (options.entry_data.entry_label) 122 | { 123 | l = gtk_label_new (NULL); 124 | if (options.data.no_markup) 125 | gtk_label_set_text_with_mnemonic (GTK_LABEL (l), options.entry_data.entry_label); 126 | else 127 | gtk_label_set_markup_with_mnemonic (GTK_LABEL (l), options.entry_data.entry_label); 128 | gtk_widget_set_name (l, "yad-entry-label"); 129 | gtk_box_pack_start (GTK_BOX (w), l, FALSE, FALSE, 1); 130 | } 131 | 132 | if (options.entry_data.numeric) 133 | { 134 | gdouble min, max, step, val; 135 | guint prec; 136 | 137 | min = 0.0; 138 | max = 65535.0; 139 | step = 1.0; 140 | prec = 0; 141 | val = 0.0; 142 | 143 | if (options.extra_data && options.extra_data[0]) 144 | { 145 | min = g_ascii_strtod (options.extra_data[0], NULL); 146 | if (options.extra_data[1]) 147 | { 148 | max = g_ascii_strtod (options.extra_data[1], NULL); 149 | if (options.extra_data[2]) 150 | { 151 | step = g_ascii_strtod (options.extra_data[2], NULL); 152 | if (options.extra_data[3]) 153 | { 154 | prec = (guint) g_ascii_strtoull (options.extra_data[3], NULL, 0); 155 | if (prec > 20) 156 | prec = 20; 157 | } 158 | } 159 | } 160 | } 161 | 162 | c = entry = gtk_spin_button_new_with_range (min, max, step); 163 | gtk_entry_set_alignment (GTK_ENTRY (c), 1.0); 164 | gtk_spin_button_set_digits (GTK_SPIN_BUTTON (c), prec); 165 | gtk_widget_set_name (entry, "yad-entry-spin"); 166 | 167 | if (options.entry_data.entry_text) 168 | { 169 | val = g_ascii_strtod (options.entry_data.entry_text, NULL); 170 | 171 | if (min >= max) 172 | { 173 | g_printerr (_("Maximum value must be greater than minimum value.\n")); 174 | min = 0.0; 175 | max = 65535.0; 176 | } 177 | 178 | if (val < min) 179 | { 180 | g_printerr (_("Initial value less than minimal.\n")); 181 | val = min; 182 | } 183 | else if (val > max) 184 | { 185 | g_printerr (_("Initial value greater than maximum.\n")); 186 | val = max; 187 | } 188 | } 189 | 190 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (c), val); 191 | } 192 | else if (!options.entry_data.completion && options.extra_data && *options.extra_data) 193 | { 194 | gint active, i; 195 | 196 | if (options.common_data.editable || settings.combo_always_editable) 197 | { 198 | c = gtk_combo_box_text_new_with_entry (); 199 | gtk_widget_set_name (c, "yad-entry-edit-combo"); 200 | entry = gtk_bin_get_child (GTK_BIN (c)); 201 | if (options.entry_data.licon) 202 | { 203 | GdkPixbuf *pb = get_pixbuf (options.entry_data.licon, YAD_SMALL_ICON, TRUE); 204 | 205 | if (pb) 206 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, pb); 207 | } 208 | if (options.entry_data.ricon) 209 | { 210 | GdkPixbuf *pb = get_pixbuf (options.entry_data.ricon, YAD_SMALL_ICON, TRUE); 211 | 212 | if (pb) 213 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, pb); 214 | } 215 | } 216 | else 217 | { 218 | c = entry = gtk_combo_box_text_new (); 219 | gtk_widget_set_name (c, "yad-entry-combo"); 220 | is_combo = TRUE; 221 | } 222 | 223 | i = 0; 224 | active = -1; 225 | while (options.extra_data[i] != NULL) 226 | { 227 | if (options.entry_data.entry_text && 228 | g_ascii_strcasecmp (options.extra_data[i], options.entry_data.entry_text) == 0) 229 | active = i; 230 | gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (c), options.extra_data[i]); 231 | i++; 232 | } 233 | 234 | if (options.entry_data.entry_text && active == -1) 235 | { 236 | gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (c), options.entry_data.entry_text); 237 | } 238 | 239 | /* set first iter active */ 240 | if (!options.common_data.editable) 241 | gtk_combo_box_set_active (GTK_COMBO_BOX (c), (active != -1 ? active : 0)); 242 | } 243 | else 244 | { 245 | c = entry = gtk_entry_new (); 246 | gtk_widget_set_name (c, "yad-entry-widget"); 247 | 248 | gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE); 249 | 250 | if (options.entry_data.entry_text) 251 | gtk_entry_set_text (GTK_ENTRY (entry), options.entry_data.entry_text); 252 | 253 | if (options.common_data.hide_text) 254 | g_object_set (G_OBJECT (entry), "visibility", FALSE, NULL); 255 | 256 | if (options.entry_data.completion) 257 | { 258 | GtkEntryCompletion *completion; 259 | GtkTreeModel *completion_model; 260 | 261 | completion = gtk_entry_completion_new (); 262 | gtk_entry_set_completion (GTK_ENTRY (entry), completion); 263 | 264 | completion_model = create_completion_model (); 265 | gtk_entry_completion_set_model (completion, completion_model); 266 | g_object_unref (completion_model); 267 | 268 | gtk_entry_completion_set_text_column (completion, 0); 269 | 270 | if (options.common_data.complete != YAD_COMPLETE_SIMPLE) 271 | gtk_entry_completion_set_match_func (completion, check_complete, NULL, NULL); 272 | 273 | g_object_unref (completion); 274 | } 275 | 276 | if (options.entry_data.licon) 277 | { 278 | GdkPixbuf *pb = get_pixbuf (options.entry_data.licon, YAD_SMALL_ICON, TRUE); 279 | 280 | if (pb) 281 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, pb); 282 | } 283 | if (options.entry_data.ricon) 284 | { 285 | GdkPixbuf *pb = get_pixbuf (options.entry_data.ricon, YAD_SMALL_ICON, TRUE); 286 | 287 | if (pb) 288 | gtk_entry_set_icon_from_pixbuf (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, pb); 289 | } 290 | } 291 | 292 | if (l) 293 | gtk_label_set_mnemonic_widget (GTK_LABEL (l), entry); 294 | 295 | if (!is_combo) 296 | g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (entry_activate_cb), dlg); 297 | else 298 | g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK (combo_activate_cb), dlg); 299 | 300 | if (options.entry_data.licon || options.entry_data.ricon) 301 | g_signal_connect (G_OBJECT (entry), "icon-press", G_CALLBACK (icon_cb), NULL); 302 | 303 | gtk_box_pack_start (GTK_BOX (w), c, TRUE, TRUE, 1); 304 | 305 | return w; 306 | } 307 | 308 | void 309 | entry_print_result (void) 310 | { 311 | if (options.entry_data.numeric) 312 | { 313 | guint prec = gtk_spin_button_get_digits (GTK_SPIN_BUTTON (entry)); 314 | g_print ("%.*f\n", prec, gtk_spin_button_get_value (GTK_SPIN_BUTTON (entry))); 315 | } 316 | else if (is_combo) 317 | { 318 | if (options.common_data.num_output) 319 | g_print ("%d\n", gtk_combo_box_get_active (GTK_COMBO_BOX (entry)) + 1); 320 | else 321 | { 322 | g_print ("%s\n", gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (entry))); 323 | } 324 | } 325 | else 326 | g_print ("%s\n", gtk_entry_get_text (GTK_ENTRY (entry))); 327 | } 328 | -------------------------------------------------------------------------------- /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, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | #include 23 | #pragma GCC diagnostic push 24 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 25 | #include 26 | #pragma GCC diagnostic pop 27 | #include 28 | 29 | #ifdef HAVE_SPELL 30 | #include 31 | #endif 32 | 33 | #ifdef HAVE_SOURCEVIEW 34 | #pragma GCC diagnostic push 35 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 36 | #if GTK_CHECK_VERSION(3,0,0) 37 | #include 38 | #else 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #endif 46 | #pragma GCC diagnostic pop 47 | #endif /* HAVE_SOURCEVIEW */ 48 | 49 | #include "cpicker.h" 50 | 51 | typedef enum { 52 | PANGO_SPEC, 53 | XFT_SPEC 54 | } FontType; 55 | 56 | static gboolean set_font_type (const gchar *name, const gchar *val, gpointer d, GError **err); 57 | static gboolean set_size_type (const gchar *name, const gchar *val, gpointer d, GError **err); 58 | 59 | static FontType font_type = XFT_SPEC; 60 | 61 | static gboolean pfd_mode = FALSE; 62 | static gboolean icon_mode = FALSE; 63 | static gboolean color_mode = FALSE; 64 | static gboolean mime = FALSE; 65 | static gboolean ver = FALSE; 66 | #ifdef HAVE_SPELL 67 | static gboolean langs_mode = FALSE; 68 | #endif 69 | #ifdef HAVE_SOURCEVIEW 70 | static gboolean themes_mode = FALSE; 71 | #endif 72 | gboolean pick_color = FALSE; 73 | 74 | static guint icon_size = 24; 75 | static gchar *icon_theme_name = NULL; 76 | 77 | static gchar **args = NULL; 78 | 79 | static GOptionEntry ents[] = { 80 | { "version", 'v', 0, G_OPTION_ARG_NONE, &ver, N_("Print version"), NULL }, 81 | #ifdef HAVE_SPELL 82 | { "show-langs", 0, 0, G_OPTION_ARG_NONE, &langs_mode, N_("Show list of spell languages"), NULL }, 83 | #endif 84 | #ifdef HAVE_SOURCEVIEW 85 | { "show-themes", 0, 0, G_OPTION_ARG_NONE, &themes_mode, N_("Show list of GtkSourceView themes"), NULL }, 86 | #endif 87 | { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args, NULL, N_("STRING ...") }, 88 | { NULL } 89 | }; 90 | 91 | static GOptionEntry pfd_ents[] = { 92 | { "pfd", 'f', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &pfd_mode, N_("Pango fonts description tools"), NULL }, 93 | { "xft", 'x', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, set_font_type, N_("Print font name in xft format"), NULL }, 94 | { "pango", 'p', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, set_font_type, N_("Print font name in pango format"), NULL }, 95 | { NULL } 96 | }; 97 | 98 | static GOptionEntry icon_ents[] = { 99 | { "icon", 'i', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &icon_mode, N_("Icon tools"), NULL }, 100 | { "mime", 'm', 0, G_OPTION_ARG_NONE, &mime, N_("Get icon name for mime type"), NULL }, 101 | { "size", 's', 0, G_OPTION_ARG_INT, &icon_size, N_("Use specified icon size"), N_("SIZE") }, 102 | { "type", 't', 0, G_OPTION_ARG_CALLBACK, set_size_type, N_("Get icon size from GtkIconSize type"), N_("TYPE") }, 103 | { "theme", 0, 0, G_OPTION_ARG_STRING, &icon_theme_name, N_("Use icon theme"), N_("THEME") }, 104 | { NULL } 105 | }; 106 | 107 | static GOptionEntry color_ents[] = { 108 | { "color", 'c', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &color_mode, N_("Color manipulation tools"), NULL }, 109 | { "pick", 0, 0, G_OPTION_ARG_NONE, &pick_color, N_("Pick up screen color"), NULL }, 110 | { NULL } 111 | }; 112 | 113 | static gboolean 114 | set_font_type (const gchar *name, const gchar *val, gpointer d, GError **err) 115 | { 116 | gint i = 1; 117 | 118 | if (name[i] == '-') 119 | i = 2; 120 | 121 | if (name[i] == 'p') 122 | font_type = PANGO_SPEC; 123 | else if (name[i] == 'x') 124 | font_type = XFT_SPEC; 125 | else 126 | return FALSE; 127 | 128 | return TRUE; 129 | } 130 | 131 | static gboolean 132 | set_size_type (const gchar *name, const gchar *val, gpointer d, GError **err) 133 | { 134 | gint w = 0, h = 0; 135 | 136 | if (strcasecmp (val, "MENU") == 0) 137 | gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); 138 | else if (strcasecmp (val, "BUTTON") == 0) 139 | gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); 140 | else if (strcasecmp (val, "SMALL_TOOLBAR") == 0) 141 | gtk_icon_size_lookup (GTK_ICON_SIZE_SMALL_TOOLBAR, &w, &h); 142 | else if (strcasecmp (val, "LARGE_TOOLBAR") == 0) 143 | gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &w, &h); 144 | else if (strcasecmp (val, "DND") == 0) 145 | gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &w, &h); 146 | else if (strcasecmp (val, "DIALOG") == 0) 147 | gtk_icon_size_lookup (GTK_ICON_SIZE_DIALOG, &w, &h); 148 | 149 | if (w && h) 150 | icon_size = MIN (w, h); 151 | 152 | return TRUE; 153 | } 154 | 155 | static gchar * 156 | parse_font (gchar *fn) 157 | { 158 | gchar **fnt; 159 | gint i = 1; 160 | GString *pfd = g_string_new (NULL); 161 | 162 | fnt = g_strsplit (fn, ":", -1); 163 | 164 | if (g_ascii_strcasecmp (fnt[0], "xft") != 0) 165 | return fnt[0]; 166 | 167 | while (fnt[i]) 168 | { 169 | if (g_ascii_strncasecmp (fnt[i], "style=", 6) == 0) 170 | g_string_append_printf (pfd, "%s ", fnt[i] + 6); 171 | else if (g_ascii_strncasecmp (fnt[i], "size=", 5) == 0) 172 | g_string_append_printf (pfd, "%s ", fnt[i] + 5); 173 | else if (g_ascii_strncasecmp (fnt[i], "pixelsize=", 10) == 0) 174 | g_string_append_printf (pfd, "%spx ", fnt[i] + 10); 175 | else 176 | g_string_append_printf (pfd, "%s ", fnt[i]); 177 | i++; 178 | } 179 | 180 | return pfd->str; 181 | } 182 | 183 | static gint 184 | run_pfd_mode () 185 | { 186 | PangoFontDescription *fnd = NULL; 187 | 188 | if (!args || !args[0]) 189 | { 190 | g_printerr (_("no font specified\n")); 191 | return 1; 192 | } 193 | 194 | /* parse font */ 195 | fnd = pango_font_description_from_string (parse_font (args[0])); 196 | if (!fnd) 197 | { 198 | g_printerr (_("cannot get font description for for string \"%s\"\n"), args[0]); 199 | return 1; 200 | } 201 | 202 | /* print font */ 203 | switch (font_type) 204 | { 205 | case PANGO_SPEC: 206 | g_print ("%s\n", pango_font_description_to_string (fnd)); 207 | break; 208 | case XFT_SPEC: 209 | { 210 | PangoFontMask mask = pango_font_description_get_set_fields (fnd); 211 | 212 | if (mask & PANGO_FONT_MASK_FAMILY) 213 | g_print ("xft:%s", pango_font_description_get_family (fnd)); 214 | else 215 | g_print ("xft:Sans"); /* simple default */ 216 | 217 | if (mask & PANGO_FONT_MASK_WEIGHT) 218 | { 219 | switch (pango_font_description_get_weight (fnd)) 220 | { 221 | case PANGO_WEIGHT_THIN: 222 | g_print (":Thin"); 223 | break; 224 | case PANGO_WEIGHT_ULTRALIGHT: 225 | g_print (":Ultralight"); 226 | break; 227 | case PANGO_WEIGHT_LIGHT: 228 | g_print (":Light"); 229 | break; 230 | case PANGO_WEIGHT_SEMILIGHT: 231 | g_print (":Semilight"); 232 | break; 233 | case PANGO_WEIGHT_BOOK: 234 | g_print (":Book"); 235 | break; 236 | case PANGO_WEIGHT_NORMAL: 237 | break; 238 | case PANGO_WEIGHT_MEDIUM: 239 | g_print (":Medium"); 240 | break; 241 | case PANGO_WEIGHT_SEMIBOLD: 242 | g_print (":Semibold"); 243 | break; 244 | case PANGO_WEIGHT_BOLD: 245 | g_print (":Bold"); 246 | break; 247 | case PANGO_WEIGHT_ULTRABOLD: 248 | g_print (":Ultrabold"); 249 | break; 250 | case PANGO_WEIGHT_HEAVY: 251 | g_print (":Heavy"); 252 | break; 253 | case PANGO_WEIGHT_ULTRAHEAVY: 254 | g_print (":Ultraheavy"); 255 | break; 256 | } 257 | } 258 | 259 | if (mask & PANGO_FONT_MASK_STYLE) 260 | { 261 | switch (pango_font_description_get_style (fnd)) 262 | { 263 | case PANGO_STYLE_NORMAL: 264 | break; 265 | case PANGO_STYLE_OBLIQUE: 266 | g_print (":Oblique"); 267 | break; 268 | case PANGO_STYLE_ITALIC: 269 | g_print (":Italic"); 270 | break; 271 | } 272 | } 273 | 274 | if (mask & PANGO_FONT_MASK_SIZE) 275 | { 276 | if (pango_font_description_get_size_is_absolute (fnd)) 277 | g_print (":pixelsize=%d", pango_font_description_get_size (fnd) / PANGO_SCALE); 278 | else 279 | g_print (":size=%d", pango_font_description_get_size (fnd) / PANGO_SCALE); 280 | } 281 | 282 | g_print ("\n"); 283 | 284 | break; 285 | } 286 | } 287 | 288 | return 0; 289 | } 290 | 291 | static gint 292 | run_icon_mode () 293 | { 294 | GtkIconTheme *theme; 295 | GtkIconInfo *ii; 296 | gchar *output = NULL; 297 | 298 | if (!args || !args[0]) 299 | { 300 | g_printerr (_("no icon specified\n")); 301 | return 1; 302 | } 303 | 304 | if (icon_theme_name) 305 | { 306 | theme = gtk_icon_theme_new (); 307 | gtk_icon_theme_set_custom_theme (theme, icon_theme_name); 308 | } 309 | else 310 | theme = gtk_icon_theme_get_default (); 311 | 312 | if (mime) 313 | { 314 | gchar *ctype = g_content_type_from_mime_type (args[0]); 315 | output = g_content_type_get_generic_icon_name (ctype); 316 | } 317 | else 318 | { 319 | ii = gtk_icon_theme_lookup_icon (theme, args[0], icon_size, 0); 320 | if (ii == NULL) 321 | return 1; 322 | output = (gchar *) gtk_icon_info_get_filename (ii); 323 | } 324 | 325 | if (output) 326 | g_print ("%s\n", output); 327 | else 328 | return 1; 329 | 330 | return 0; 331 | } 332 | 333 | static gint 334 | run_color_mode () 335 | { 336 | if (pick_color) 337 | { 338 | gtk_init (NULL, NULL); 339 | yad_get_screen_color (NULL); 340 | gtk_main (); 341 | } 342 | 343 | return 0; 344 | } 345 | 346 | #ifdef HAVE_SPELL 347 | static gint 348 | show_langs () 349 | { 350 | const GList *lng; 351 | 352 | for (lng = gtk_spell_checker_get_language_list (); lng; lng = lng->next) 353 | g_print ("%s\n", (gchar *) lng->data); 354 | 355 | return 0; 356 | } 357 | #endif 358 | 359 | #ifdef HAVE_SOURCEVIEW 360 | static gint 361 | show_themes () 362 | { 363 | GtkSourceStyleSchemeManager *sm; 364 | const gchar **si; 365 | guint i = 0; 366 | 367 | sm = gtk_source_style_scheme_manager_get_default (); 368 | if ((si = (const gchar **) gtk_source_style_scheme_manager_get_scheme_ids (sm)) == NULL) 369 | return 1; 370 | 371 | while (si[i]) 372 | { 373 | GtkSourceStyleScheme *s = gtk_source_style_scheme_manager_get_scheme (sm, si[i]); 374 | g_print ("%s\n", gtk_source_style_scheme_get_name (s)); 375 | i++; 376 | } 377 | 378 | return 0; 379 | } 380 | #endif 381 | 382 | int 383 | main (int argc, char *argv[]) 384 | { 385 | GOptionContext *ctx; 386 | GOptionGroup *grp; 387 | GError *err = NULL; 388 | gint ret = 0; 389 | 390 | setlocale (LC_ALL, ""); 391 | 392 | #ifdef ENABLE_NLS 393 | bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); 394 | bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 395 | textdomain (GETTEXT_PACKAGE); 396 | #endif 397 | 398 | gtk_init (&argc, &argv); 399 | 400 | ctx = g_option_context_new (_("- yad miscellaneous tools")); 401 | g_option_context_add_main_entries (ctx, ents, GETTEXT_PACKAGE); 402 | 403 | grp = g_option_group_new ("pfd", _("PFD mode"), _("Show pfd mode options"), NULL, NULL); 404 | g_option_group_add_entries (grp, pfd_ents); 405 | g_option_group_set_translation_domain (grp, GETTEXT_PACKAGE); 406 | g_option_context_add_group (ctx, grp); 407 | 408 | grp = g_option_group_new ("icon", _("Icon mode"), _("Show icon mode options"), NULL, NULL); 409 | g_option_group_add_entries (grp, icon_ents); 410 | g_option_group_set_translation_domain (grp, GETTEXT_PACKAGE); 411 | g_option_context_add_group (ctx, grp); 412 | 413 | grp = g_option_group_new ("color", _("Color mode"), _("Show color mode options"), NULL, NULL); 414 | g_option_group_add_entries (grp, color_ents); 415 | g_option_group_set_translation_domain (grp, GETTEXT_PACKAGE); 416 | g_option_context_add_group (ctx, grp); 417 | 418 | if (!g_option_context_parse (ctx, &argc, &argv, &err)) 419 | { 420 | g_printerr (_("option parsing failed: %s\n"), err->message); 421 | return 1; 422 | } 423 | 424 | if (ver) 425 | { 426 | g_print ("%s (GTK+ %d.%d.%d)\n", PACKAGE_VERSION, gtk_major_version, gtk_minor_version, gtk_micro_version); 427 | return 0; 428 | } 429 | 430 | if (pfd_mode) 431 | ret = run_pfd_mode (); 432 | else if (icon_mode) 433 | ret = run_icon_mode (); 434 | else if (color_mode) 435 | ret = run_color_mode (); 436 | #ifdef HAVE_SPELL 437 | else if (langs_mode) 438 | ret = show_langs (); 439 | #endif 440 | #ifdef HAVE_SOURCEVIEW 441 | else if (themes_mode) 442 | ret = show_themes (); 443 | #endif 444 | else 445 | { 446 | g_printerr (_("no mode specified\n")); 447 | return 1; 448 | } 449 | 450 | return ret; 451 | } 452 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "yad.h" 28 | 29 | typedef struct { 30 | gchar *name; 31 | gchar *action; 32 | gchar *icon; 33 | } MenuData; 34 | 35 | static GtkStatusIcon *status_icon; 36 | 37 | static gchar *icon = NULL; 38 | static gchar *action = NULL; 39 | 40 | static GSList *menu_data = NULL; 41 | 42 | static gint exit_code; 43 | 44 | static void popup_menu_cb (GtkStatusIcon *, guint, guint, gpointer); 45 | 46 | static void 47 | free_menu_data (gpointer data) 48 | { 49 | MenuData *m = (MenuData *) data; 50 | 51 | if (m) { 52 | g_free (m->name); 53 | g_free (m->action); 54 | g_free (m->icon); 55 | g_free (m); 56 | } 57 | } 58 | 59 | static void 60 | parse_menu_str (gchar * str) 61 | { 62 | gchar **menu_vals; 63 | gint i = 0; 64 | 65 | if (menu_data) 66 | { 67 | g_slist_free_full (menu_data, free_menu_data); 68 | menu_data = NULL; 69 | } 70 | 71 | menu_vals = g_strsplit (str, options.common_data.separator, -1); 72 | 73 | while (menu_vals[i] != NULL) 74 | { 75 | MenuData *mdata = g_new0 (MenuData, 1); 76 | gchar **s = g_strsplit (menu_vals[i], options.common_data.item_separator, 3); 77 | 78 | if (s[0]) 79 | { 80 | mdata->name = g_strdup (s[0]); 81 | if (s[1]) 82 | { 83 | mdata->action = g_strdup (s[1]); 84 | if (s[2]) 85 | mdata->icon = g_strdup (s[2]); 86 | } 87 | } 88 | menu_data = g_slist_append (menu_data, mdata); 89 | g_strfreev (s); 90 | i++; 91 | } 92 | 93 | g_strfreev (menu_vals); 94 | } 95 | 96 | static void 97 | timeout_cb (gpointer data) 98 | { 99 | exit_code = YAD_RESPONSE_TIMEOUT; 100 | gtk_main_quit (); 101 | } 102 | 103 | static void 104 | set_icon (void) 105 | { 106 | GdkPixbuf *pixbuf = NULL; 107 | GError *err = NULL; 108 | gboolean b; 109 | GtkStockItem sit; 110 | if (icon == NULL || *icon == '\0') 111 | { 112 | UNDEPR (gtk_status_icon_set_from_icon_name, status_icon, "yad"); 113 | return; 114 | } 115 | 116 | SETUNDEPR (b, gtk_stock_lookup, icon, &sit); 117 | if (b) 118 | { 119 | static GtkWidget *button = NULL; 120 | if (button == NULL) 121 | button = gtk_button_new (); 122 | 123 | SETUNDEPR (pixbuf, gtk_widget_render_icon, button, sit.stock_id, GTK_ICON_SIZE_SMALL_TOOLBAR, ""); 124 | } 125 | else if (g_file_test (icon, G_FILE_TEST_EXISTS)) 126 | { 127 | gint isize = (options.common_data.icon_size > 0) ? options.common_data.icon_size : 16; 128 | 129 | pixbuf = gdk_pixbuf_new_from_file_at_scale (icon, isize, isize, TRUE, &err); 130 | if (err) 131 | { 132 | g_printerr (_("Could not load notification icon '%s': %s\n"), icon, err->message); 133 | g_clear_error (&err); 134 | } 135 | } 136 | else 137 | UNDEPR (gtk_status_icon_set_from_icon_name, status_icon, icon); 138 | if (pixbuf) 139 | { 140 | UNDEPR (gtk_status_icon_set_from_pixbuf, status_icon, pixbuf); 141 | g_object_unref (pixbuf); 142 | } 143 | } 144 | 145 | static gboolean 146 | activate_cb (GtkWidget * widget, YadData * data) 147 | { 148 | if ((action == NULL && !options.common_data.listen) || (action && g_ascii_strcasecmp (action, "quit") == 0)) 149 | { 150 | exit_code = YAD_RESPONSE_OK; 151 | gtk_main_quit (); 152 | } 153 | else if (action) 154 | { 155 | if (g_ascii_strcasecmp (action, "menu") == 0) 156 | popup_menu_cb (GTK_STATUS_ICON (widget), 1, GDK_CURRENT_TIME, data); 157 | else 158 | run_command_async (action); 159 | } 160 | 161 | return TRUE; 162 | } 163 | 164 | static gboolean 165 | middle_quit_cb (GtkStatusIcon * icon, GdkEventButton * ev, gpointer data) 166 | { 167 | if (ev->button == 2) 168 | { 169 | if (options.data.escape_ok) 170 | exit_code = YAD_RESPONSE_OK; 171 | else 172 | exit_code = YAD_RESPONSE_ESC; 173 | gtk_main_quit (); 174 | } 175 | 176 | return FALSE; 177 | } 178 | 179 | static void 180 | popup_menu_item_activate_cb (GtkWidget * w, gpointer data) 181 | { 182 | gchar *cmd = (gchar *) data; 183 | 184 | if (cmd) 185 | { 186 | if (g_ascii_strcasecmp (g_strstrip (cmd), "quit") == 0) 187 | { 188 | exit_code = YAD_RESPONSE_OK; 189 | gtk_main_quit (); 190 | } 191 | else 192 | run_command_async (cmd); 193 | } 194 | } 195 | 196 | static void 197 | popup_menu_cb (GtkStatusIcon *icon, guint button, guint activate_time, gpointer data) 198 | { 199 | GtkWidget *menu; 200 | GtkWidget *item; 201 | GSList *m; 202 | 203 | if (!menu_data) 204 | return; 205 | 206 | menu = gtk_menu_new (); 207 | gtk_menu_set_reserve_toggle_size (GTK_MENU (menu), FALSE); 208 | 209 | for (m = menu_data; m; m = m->next) 210 | { 211 | MenuData *d = (MenuData *) m->data; 212 | GtkStockItem it; 213 | gboolean b; 214 | 215 | if (d->name) 216 | { 217 | if (d->icon) 218 | { 219 | SETUNDEPR (b, gtk_stock_lookup, d->icon, &it); 220 | if (b) 221 | { 222 | SETUNDEPR (item, gtk_image_menu_item_new_from_stock, d->icon, NULL); 223 | gtk_menu_item_set_label (GTK_MENU_ITEM (item), d->name); 224 | } 225 | else 226 | { 227 | GdkPixbuf *pb = get_pixbuf (d->icon, YAD_SMALL_ICON, TRUE); 228 | SETUNDEPR (item, gtk_image_menu_item_new_with_mnemonic, d->name); 229 | if (pb) 230 | { 231 | UNDEPR (gtk_image_menu_item_set_image, GTK_IMAGE_MENU_ITEM (item), gtk_image_new_from_pixbuf (pb)); 232 | g_object_unref (pb); 233 | } 234 | } 235 | } 236 | else 237 | { 238 | SETUNDEPR (b, gtk_stock_lookup, d->name, &it); 239 | if (b) 240 | { 241 | SETUNDEPR (item, gtk_image_menu_item_new_from_stock, d->name, NULL); 242 | } 243 | else 244 | item = gtk_menu_item_new_with_mnemonic (d->name); 245 | } 246 | g_signal_connect (GTK_MENU_ITEM (item), "activate", 247 | G_CALLBACK (popup_menu_item_activate_cb), (gpointer) d->action); 248 | } 249 | else 250 | item = gtk_separator_menu_item_new (); 251 | 252 | gtk_widget_show (item); 253 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); 254 | } 255 | UNDEPR (gtk_menu_popup, GTK_MENU (menu), NULL, NULL, gtk_status_icon_position_menu, icon, button, activate_time); 256 | } 257 | 258 | static gboolean 259 | handle_stdin (GIOChannel * channel, GIOCondition condition, gpointer data) 260 | { 261 | if ((condition & G_IO_IN) != 0) 262 | { 263 | GString *string; 264 | GError *err = NULL; 265 | 266 | string = g_string_new (NULL); 267 | while (channel->is_readable == FALSE) 268 | usleep (100); 269 | 270 | do 271 | { 272 | gint status; 273 | gchar *command = NULL, *value = NULL, **args; 274 | 275 | do 276 | { 277 | status = g_io_channel_read_line_string (channel, string, NULL, &err); 278 | 279 | while (gdk_events_pending ()) 280 | gtk_main_iteration (); 281 | } 282 | while (status == G_IO_STATUS_AGAIN); 283 | 284 | if (status != G_IO_STATUS_NORMAL) 285 | { 286 | if (err) 287 | { 288 | g_printerr ("yad_notification_handle_stdin(): %s\n", err->message); 289 | g_error_free (err); 290 | err = NULL; 291 | } 292 | /* stop handling but not exit */ 293 | g_io_channel_shutdown (channel, TRUE, NULL); 294 | return FALSE; 295 | } 296 | 297 | strip_new_line (string->str); 298 | if (!string->str[0]) 299 | continue; 300 | 301 | args = g_strsplit (string->str, ":", 2); 302 | command = g_strdup (args[0]); 303 | if (args[1]) 304 | value = g_strdup (args[1]); 305 | g_strfreev (args); 306 | if (value) 307 | g_strstrip (value); 308 | 309 | if (!g_ascii_strcasecmp (command, "icon") && value) 310 | { 311 | g_free (icon); 312 | icon = g_strdup (value); 313 | 314 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 315 | if (gtk_status_icon_get_visible (status_icon) && gtk_status_icon_is_embedded (status_icon)) 316 | set_icon (); 317 | G_GNUC_END_IGNORE_DEPRECATIONS; 318 | } 319 | else if (!g_ascii_strcasecmp (command, "tooltip")) 320 | { 321 | if (g_utf8_validate (value, -1, NULL)) 322 | { 323 | gchar *message = g_strcompress (value); 324 | if (!options.data.no_markup) 325 | { 326 | UNDEPR (gtk_status_icon_set_tooltip_markup, status_icon, message); 327 | } 328 | else 329 | { 330 | UNDEPR (gtk_status_icon_set_tooltip_text, status_icon, message); 331 | } 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 !GTK_CHECK_VERSION(3,0,0) 341 | if (!g_ascii_strcasecmp (value, "blink")) 342 | { 343 | gboolean state = gtk_status_icon_get_blinking (status_icon); 344 | gtk_status_icon_set_blinking (status_icon, !state); 345 | } 346 | else 347 | #endif 348 | if (!g_ascii_strcasecmp (value, "false")) 349 | { 350 | gtk_status_icon_set_visible (status_icon, FALSE); 351 | #if !GTK_CHECK_VERSION(3,0,0) 352 | gtk_status_icon_set_blinking (status_icon, FALSE); 353 | #endif 354 | } 355 | else 356 | { 357 | gtk_status_icon_set_visible (status_icon, TRUE); 358 | #if !GTK_CHECK_VERSION(3,0,0) 359 | gtk_status_icon_set_blinking (status_icon, FALSE); 360 | #endif 361 | } 362 | G_GNUC_END_IGNORE_DEPRECATIONS; 363 | } 364 | else if (!g_ascii_strcasecmp (command, "action")) 365 | { 366 | g_free (action); 367 | if (value) 368 | action = g_strdup (value); 369 | } 370 | else if (!g_ascii_strcasecmp (command, "quit")) 371 | { 372 | exit_code = YAD_RESPONSE_OK; 373 | gtk_main_quit (); 374 | } 375 | else if (!g_ascii_strcasecmp (command, "menu")) 376 | { 377 | if (value) 378 | parse_menu_str (value); 379 | } 380 | else 381 | g_printerr (_("Unknown command '%s'\n"), command); 382 | 383 | g_free (command); 384 | g_free (value); 385 | } 386 | while (g_io_channel_get_buffer_condition (channel) == G_IO_IN); 387 | g_string_free (string, TRUE); 388 | } 389 | 390 | if ((condition & G_IO_HUP) != 0) 391 | { 392 | g_io_channel_shutdown (channel, TRUE, NULL); 393 | gtk_main_quit (); 394 | return FALSE; 395 | } 396 | 397 | return TRUE; 398 | } 399 | 400 | gint 401 | yad_notification_run () 402 | { 403 | GIOChannel *channel = NULL; 404 | 405 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS; 406 | status_icon = gtk_status_icon_new (); 407 | 408 | if (options.data.dialog_text) 409 | { 410 | if (!options.data.no_markup) 411 | gtk_status_icon_set_tooltip_markup (status_icon, options.data.dialog_text); 412 | else 413 | gtk_status_icon_set_tooltip_text (status_icon, options.data.dialog_text); 414 | } 415 | else 416 | gtk_status_icon_set_tooltip_text (status_icon, _("Yad notification")); 417 | G_GNUC_END_IGNORE_DEPRECATIONS; 418 | 419 | if (options.data.dialog_image) 420 | icon = g_strdup (options.data.dialog_image); 421 | if (options.common_data.command) 422 | action = g_strdup (options.common_data.command); 423 | 424 | set_icon (); 425 | 426 | g_signal_connect (status_icon, "activate", G_CALLBACK (activate_cb), NULL); 427 | g_signal_connect (status_icon, "popup_menu", G_CALLBACK (popup_menu_cb), NULL); 428 | 429 | if (options.notification_data.menu) 430 | parse_menu_str (options.notification_data.menu); 431 | 432 | /* quit on middle click (like press Esc) */ 433 | if (options.notification_data.middle) 434 | g_signal_connect (status_icon, "button-press-event", G_CALLBACK (middle_quit_cb), NULL); 435 | 436 | if (options.common_data.listen) 437 | { 438 | channel = g_io_channel_unix_new (0); 439 | if (channel) 440 | { 441 | g_io_channel_set_encoding (channel, NULL, NULL); 442 | g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); 443 | g_io_add_watch (channel, G_IO_IN | G_IO_HUP, handle_stdin, NULL); 444 | } 445 | } 446 | 447 | /* Show icon and wait */ 448 | UNDEPR (gtk_status_icon_set_visible, status_icon, !options.notification_data.hidden); 449 | 450 | if (options.data.timeout > 0) 451 | g_timeout_add_seconds (options.data.timeout, (GSourceFunc) timeout_cb, NULL); 452 | 453 | gtk_main (); 454 | 455 | return exit_code; 456 | } 457 | -------------------------------------------------------------------------------- /src/html_gtk2.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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #include "yad.h" 25 | 26 | #ifdef USE_WEBKIT2 27 | #include 28 | #else 29 | #include 30 | #endif 31 | 32 | static WebKitWebView *view; 33 | 34 | static GString *inbuf; 35 | 36 | #ifdef USE_WEBKIT2 37 | static gboolean is_loaded = FALSE; 38 | #else 39 | static gboolean is_link = FALSE; 40 | #endif 41 | 42 | #ifndef PATH_MAX 43 | #define PATH_MAX 4096 44 | #endif 45 | 46 | static void 47 | load_uri (const gchar * uri) 48 | { 49 | gchar *addr = NULL; 50 | 51 | if (!uri || !uri[0]) 52 | return; 53 | 54 | if (g_file_test (uri, G_FILE_TEST_EXISTS)) 55 | { 56 | if (g_path_is_absolute (uri)) 57 | addr = g_filename_to_uri (uri, NULL, NULL); 58 | else 59 | { 60 | gchar *afn = g_new0 (gchar, PATH_MAX); 61 | realpath (uri, afn); 62 | addr = g_filename_to_uri (afn, NULL, NULL); 63 | g_free (afn); 64 | } 65 | } 66 | else 67 | { 68 | if (g_uri_parse_scheme (uri) == NULL) 69 | addr = g_strdup_printf ("https://%s", uri); 70 | else 71 | addr = g_strdup (uri); 72 | } 73 | 74 | if (addr) 75 | { 76 | webkit_web_view_load_uri (view, addr); 77 | g_free (addr); 78 | } 79 | else 80 | g_printerr ("yad_html_load_uri: cannot load uri '%s'\n", uri); 81 | } 82 | 83 | #ifndef USE_WEBKIT2 84 | 85 | static gboolean 86 | link_cb (WebKitWebView * v, WebKitWebFrame * f, WebKitNetworkRequest * r, 87 | WebKitWebNavigationAction * act, WebKitWebPolicyDecision * pd, gpointer d) 88 | { 89 | gchar *uri; 90 | 91 | if (webkit_web_navigation_action_get_reason (act) != WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED) 92 | { 93 | /* skip handling non clicked reasons */ 94 | webkit_web_policy_decision_use (pd); 95 | return TRUE; 96 | } 97 | 98 | uri = (gchar *) webkit_network_request_get_uri (r); 99 | 100 | if (!options.html_data.browser) 101 | { 102 | if (options.html_data.print_uri) 103 | g_printf ("%s\n", uri); 104 | else 105 | { 106 | gchar *cmd = g_strdup_printf (settings.open_cmd, uri); 107 | g_spawn_command_line_async (cmd, NULL); 108 | g_free (cmd); 109 | } 110 | webkit_web_policy_decision_ignore (pd); 111 | } 112 | else 113 | { 114 | if (options.html_data.uri_cmd) 115 | { 116 | gint ret = -1; 117 | gchar *cmd = g_strdup_printf (options.html_data.uri_cmd, uri); 118 | static gchar *vb = NULL, *vm = NULL; 119 | 120 | /* set environment */ 121 | g_free (vb); 122 | vb = g_strdup_printf ("%d", webkit_web_navigation_action_get_button (act)); 123 | g_setenv ("YAD_HTML_BUTTON", vb, TRUE); 124 | g_free (vm); 125 | vm = g_strdup_printf ("%d", webkit_web_navigation_action_get_modifier_state (act)); 126 | g_setenv ("YAD_HTML_KEYS", vm, TRUE); 127 | 128 | /* run handler */ 129 | ret = run_command_sync (cmd, NULL, NULL); 130 | /* actual exit code in highest byte */ 131 | switch (ret >> 8) 132 | { 133 | case 0: 134 | webkit_web_policy_decision_use (pd); 135 | break; 136 | case 1: 137 | webkit_web_policy_decision_ignore (pd); 138 | break; 139 | case 2: 140 | webkit_web_policy_decision_download (pd); 141 | break; 142 | default: 143 | g_printerr ("yad: undefined return code (%d) from uri handler\n", ret >> 8); 144 | webkit_web_policy_decision_ignore (pd); 145 | break; 146 | } 147 | g_free (cmd); 148 | } 149 | else 150 | webkit_web_policy_decision_use (pd); 151 | } 152 | 153 | return TRUE; 154 | } 155 | 156 | static void 157 | link_hover_cb (WebKitWebView * v, const gchar * t, const gchar * link, gpointer * d) 158 | { 159 | is_link = (link != NULL); 160 | } 161 | 162 | #else 163 | 164 | static void 165 | loaded_cb (WebKitWebView *v, WebKitLoadEvent ev, gpointer d) 166 | { 167 | if (ev == WEBKIT_LOAD_FINISHED) 168 | is_loaded = TRUE; 169 | } 170 | 171 | static gboolean 172 | policy_cb (WebKitWebView *v, WebKitPolicyDecision *pd, WebKitPolicyDecisionType pt, gpointer d) 173 | { 174 | if (is_loaded && !options.html_data.browser) 175 | { 176 | WebKitNavigationAction *act = webkit_navigation_policy_decision_get_navigation_action (WEBKIT_NAVIGATION_POLICY_DECISION (pd)); 177 | webkit_policy_decision_ignore (pd); 178 | if (webkit_navigation_action_get_navigation_type (act) == WEBKIT_NAVIGATION_TYPE_LINK_CLICKED) 179 | { 180 | WebKitURIRequest *r = webkit_navigation_action_get_request (act); 181 | gchar *uri = (gchar *) webkit_uri_request_get_uri (r); 182 | 183 | if (options.html_data.print_uri) 184 | g_printf ("%s\n", uri); 185 | else 186 | g_app_info_launch_default_for_uri (uri, NULL, NULL); 187 | } 188 | } 189 | else 190 | return FALSE; 191 | 192 | return TRUE; 193 | } 194 | 195 | #endif 196 | 197 | static void 198 | select_file_cb (GtkEntry * entry, GtkEntryIconPosition pos, GdkEventButton * ev, gpointer d) 199 | { 200 | GtkWidget *dlg; 201 | static gchar *dir = NULL; 202 | 203 | if (ev->button != 1 || pos != GTK_ENTRY_ICON_SECONDARY) 204 | return; 205 | 206 | dlg = gtk_file_chooser_dialog_new (_("YAD - Select File"), 207 | GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (entry))), 208 | GTK_FILE_CHOOSER_ACTION_OPEN, 209 | GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL); 210 | if (dir) 211 | gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dlg), dir); 212 | 213 | if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT) 214 | { 215 | gchar *uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dlg)); 216 | gtk_entry_set_text (entry, uri); 217 | g_free (uri); 218 | 219 | /* keep current dir */ 220 | g_free (dir); 221 | dir = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dlg)); 222 | } 223 | 224 | gtk_widget_destroy (dlg); 225 | } 226 | 227 | static void 228 | do_open_cb (GtkWidget * w, GtkDialog * dlg) 229 | { 230 | gtk_dialog_response (dlg, GTK_RESPONSE_ACCEPT); 231 | } 232 | 233 | static void 234 | open_cb (GtkWidget * w, gpointer d) 235 | { 236 | GtkWidget *dlg, *cnt, *lbl, *entry; 237 | 238 | dlg = gtk_dialog_new_with_buttons (_("Open URI"), 239 | GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))), 240 | GTK_DIALOG_DESTROY_WITH_PARENT, 241 | GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); 242 | gtk_window_set_default_size (GTK_WINDOW (dlg), 350, -1); 243 | 244 | cnt = gtk_dialog_get_content_area (GTK_DIALOG (dlg)); 245 | 246 | lbl = gtk_label_new (_("Enter URI or file name:")); 247 | #if !GTK_CHECK_VERSION(3,0,0) 248 | gtk_misc_set_alignment (GTK_MISC (lbl), 0.0, 0.5); 249 | #else 250 | gtk_label_set_xalign (GTK_LABEL (lbl), 0.0); 251 | #endif 252 | gtk_widget_show (lbl); 253 | gtk_box_pack_start (GTK_BOX (cnt), lbl, TRUE, FALSE, 2); 254 | 255 | entry = gtk_entry_new (); 256 | gtk_entry_set_icon_from_icon_name (GTK_ENTRY (entry), GTK_ENTRY_ICON_SECONDARY, "document-open"); 257 | gtk_widget_show (entry); 258 | gtk_box_pack_start (GTK_BOX (cnt), entry, TRUE, FALSE, 2); 259 | 260 | g_signal_connect (G_OBJECT (entry), "icon-press", G_CALLBACK (select_file_cb), NULL); 261 | g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (do_open_cb), dlg); 262 | 263 | if (gtk_dialog_run (GTK_DIALOG (dlg)) == GTK_RESPONSE_ACCEPT) 264 | load_uri (gtk_entry_get_text (GTK_ENTRY (entry))); 265 | 266 | gtk_widget_destroy (dlg); 267 | } 268 | 269 | static gboolean 270 | menu_cb (WebKitWebView * view, GtkWidget * menu, WebKitHitTestResult * hit, gboolean kb, gpointer d) 271 | { 272 | GtkWidget *mi; 273 | 274 | #ifndef USE_WEBKIT2 275 | if (!is_link) 276 | { 277 | /* add open item */ 278 | mi = gtk_separator_menu_item_new (); 279 | gtk_widget_show (mi); 280 | gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); 281 | 282 | mi = gtk_image_menu_item_new_from_stock ("gtk-open", NULL); 283 | gtk_widget_show (mi); 284 | gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), mi); 285 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (open_cb), NULL); 286 | 287 | /* add quit item */ 288 | mi = gtk_separator_menu_item_new (); 289 | gtk_widget_show (mi); 290 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); 291 | 292 | mi = gtk_image_menu_item_new_from_stock ("gtk-quit", NULL); 293 | gtk_widget_show (mi); 294 | gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi); 295 | g_signal_connect (G_OBJECT (mi), "activate", G_CALLBACK (gtk_main_quit), NULL); 296 | } 297 | #endif 298 | 299 | return FALSE; 300 | } 301 | 302 | static void 303 | title_cb (GObject *obj, GParamSpec *spec, GtkWindow *dlg) 304 | { 305 | const gchar *title = webkit_web_view_get_title (view); 306 | if (title) 307 | gtk_window_set_title (dlg, title); 308 | } 309 | 310 | static void 311 | icon_cb (GObject *obj, GParamSpec *spec, GtkWindow *dlg) 312 | { 313 | #ifdef USE_WEBKIT2 314 | GdkPixbuf *pb = gdk_pixbuf_get_from_surface (webkit_web_view_get_favicon (view), 0, 0, -1, -1); 315 | #else 316 | GdkPixbuf *pb = webkit_web_view_try_get_favicon_pixbuf (view, 16, 16); 317 | #endif 318 | if (pb) 319 | { 320 | gtk_window_set_icon (dlg, pb); 321 | g_object_unref (pb); 322 | } 323 | } 324 | 325 | static gboolean 326 | handle_stdin (GIOChannel * ch, GIOCondition cond, gpointer d) 327 | { 328 | gchar *buf; 329 | #ifdef USE_WEBKIT2 330 | GBytes *data; 331 | #endif 332 | GError *err = NULL; 333 | 334 | switch (g_io_channel_read_line (ch, &buf, NULL, NULL, &err)) 335 | { 336 | case G_IO_STATUS_NORMAL: 337 | g_string_append (inbuf, buf); 338 | return TRUE; 339 | 340 | case G_IO_STATUS_ERROR: 341 | g_printerr ("yad_html_handle_stdin(): %s\n", err->message); 342 | g_error_free (err); 343 | return FALSE; 344 | 345 | case G_IO_STATUS_EOF: 346 | #ifdef USE_WEBKIT2 347 | data = g_bytes_new (inbuf->str, inbuf->len); 348 | /*g_string_free (inbuf, TRUE); */ /* FIXME: IS THAT NEEDED ??? (and where) */ 349 | webkit_web_view_load_bytes (view, data, options.html_data.mime, options.html_data.encoding, NULL); 350 | g_bytes_unref (data); 351 | #else 352 | webkit_web_view_load_string (view, inbuf->str, options.html_data.mime, options.html_data.encoding, NULL); 353 | #endif 354 | return FALSE; 355 | 356 | case G_IO_STATUS_AGAIN: 357 | return TRUE; 358 | } 359 | 360 | return FALSE; 361 | } 362 | 363 | GtkWidget * 364 | html_create_widget (GtkWidget * dlg) 365 | { 366 | GtkWidget *sw; 367 | #ifdef USE_WEBKIT2 368 | WebKitSettings *settings; 369 | #else 370 | WebKitWebSettings *settings; 371 | #endif 372 | SoupSession *sess; 373 | 374 | sw = gtk_scrolled_window_new (NULL, NULL); 375 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.hscroll_policy, options.vscroll_policy); 376 | 377 | view = WEBKIT_WEB_VIEW (webkit_web_view_new ()); 378 | gtk_container_add (GTK_CONTAINER (sw), GTK_WIDGET (view)); 379 | 380 | #ifdef USE_WEBKIT2 381 | settings = webkit_settings_new (); 382 | #else 383 | settings = webkit_web_settings_new (); 384 | #endif 385 | 386 | g_object_set (G_OBJECT (settings), "user-agent", options.html_data.user_agent, NULL); 387 | if (options.html_data.user_style) 388 | { 389 | gchar *uri = g_filename_to_uri (options.html_data.user_style, NULL, NULL); 390 | g_object_set (G_OBJECT (settings), "user-stylesheet-uri", uri, NULL); 391 | } 392 | webkit_web_view_set_settings (view, settings); 393 | 394 | #ifdef USE_WEBKIT2 395 | webkit_settings_set_default_charset (settings, g_get_codeset ()); 396 | 397 | g_signal_connect (view, "decide-policy", G_CALLBACK (policy_cb), NULL); 398 | #else 399 | g_object_set (G_OBJECT (settings), "default-encoding", g_get_codeset (), NULL); 400 | 401 | g_signal_connect (view, "hovering-over-link", G_CALLBACK (link_hover_cb), NULL); 402 | g_signal_connect (view, "navigation-policy-decision-requested", G_CALLBACK (link_cb), NULL); 403 | #endif 404 | 405 | if (options.html_data.browser) 406 | { 407 | g_signal_connect (view, "context-menu", G_CALLBACK (menu_cb), NULL); 408 | if (!options.data.dialog_title) 409 | g_signal_connect (view, "notify::title", G_CALLBACK (title_cb), dlg); 410 | if (strcmp (options.data.window_icon, "yad") == 0) 411 | #ifdef USE_WEBKIT2 412 | g_signal_connect (view, "notify::favicon", G_CALLBACK (icon_cb), dlg); 413 | #else 414 | g_signal_connect (view, "icon-loaded", G_CALLBACK (icon_cb), dlg); 415 | #endif 416 | } 417 | #ifdef USE_WEBKIT2 418 | else 419 | { 420 | g_object_set (G_OBJECT(settings), "enable-caret-browsing", FALSE, NULL); 421 | g_object_set (G_OBJECT(settings), "enable-developer-extras", FALSE, NULL); 422 | g_object_set (G_OBJECT(settings), "enable-html5-database", FALSE, NULL); 423 | g_object_set (G_OBJECT(settings), "enable-html5-local-storage", FALSE, NULL); 424 | g_object_set (G_OBJECT(settings), "enable-offline-web-application-cache", FALSE, NULL); 425 | g_object_set (G_OBJECT(settings), "enable-page-cache", FALSE, NULL); 426 | g_object_set (G_OBJECT(settings), "enable-plugins", FALSE, NULL); 427 | g_object_set (G_OBJECT (settings), "enable-private-browsing", TRUE, NULL); 428 | g_signal_connect (view, "load-changed", G_CALLBACK (loaded_cb), NULL); 429 | } 430 | #endif 431 | 432 | #ifndef USE_WEBKIT2 433 | sess = webkit_get_default_session (); 434 | soup_session_add_feature_by_type (sess, SOUP_TYPE_PROXY_RESOLVER_DEFAULT); 435 | g_object_set (G_OBJECT (sess), SOUP_SESSION_ACCEPT_LANGUAGE_AUTO, TRUE, NULL); 436 | #endif 437 | 438 | gtk_widget_show_all (sw); 439 | gtk_widget_grab_focus (GTK_WIDGET (view)); 440 | 441 | if (options.html_data.uri) 442 | load_uri (options.html_data.uri); 443 | else if (!options.html_data.browser) 444 | { 445 | GIOChannel *ch; 446 | 447 | inbuf = g_string_new (NULL); 448 | ch = g_io_channel_unix_new (0); 449 | g_io_channel_set_encoding (ch, NULL, NULL); 450 | g_io_channel_set_flags (ch, G_IO_FLAG_NONBLOCK, NULL); 451 | g_io_add_watch (ch, G_IO_IN | G_IO_HUP, handle_stdin, NULL); 452 | } 453 | else if (options.extra_data) 454 | load_uri (options.extra_data[0]); 455 | 456 | return sw; 457 | } 458 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | typedef struct { 28 | GtkWidget *win; 29 | GtkWidget *image; 30 | GtkWidget *lname; 31 | GtkWidget *lsize; 32 | GtkWidget *lfile; 33 | GtkWidget *cat_list; 34 | GtkWidget *icon_list; 35 | 36 | GtkIconTheme *theme; 37 | 38 | GHashTable *icons; 39 | } IconBrowserData; 40 | 41 | static gboolean show_regular = TRUE; 42 | static gboolean show_symbolic = FALSE; 43 | 44 | static gboolean 45 | key_press_cb (GtkWidget * w, GdkEventKey * ev, gpointer data) 46 | { 47 | if (ev->keyval == GDK_KEY_Escape) 48 | { 49 | gtk_main_quit (); 50 | return TRUE; 51 | } 52 | return FALSE; 53 | } 54 | 55 | static GtkListStore * 56 | load_icon_cat (IconBrowserData * data, gchar * cat) 57 | { 58 | GtkListStore *store; 59 | GList *i, *icons; 60 | gint size, w, h; 61 | 62 | gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &w, &h); 63 | size = MIN (w, h); 64 | 65 | store = gtk_list_store_new (2, GDK_TYPE_PIXBUF, G_TYPE_STRING); 66 | 67 | icons = gtk_icon_theme_list_icons (data->theme, cat); 68 | for (i = icons; i; i = i->next) 69 | { 70 | GtkTreeIter iter; 71 | GdkPixbuf *pb, *spb; 72 | #if GTK_CHECK_VERSION(3,0,0) 73 | GtkIconInfo *info; 74 | 75 | info = gtk_icon_theme_lookup_icon (data->theme, i->data, size, 0); 76 | if (gtk_icon_info_is_symbolic (info)) 77 | { 78 | if (!show_symbolic) 79 | continue; 80 | } 81 | else 82 | { 83 | if (!show_regular) 84 | continue; 85 | } 86 | g_object_unref (info); 87 | 88 | spb = pb = gtk_icon_theme_load_icon (data->theme, i->data, size, 0, NULL); 89 | #else 90 | /* GTK+-2 can't discriminate symbolic icons */ 91 | spb = pb = gtk_icon_theme_load_icon (data->theme, i->data, size, GTK_ICON_LOOKUP_GENERIC_FALLBACK, NULL); 92 | #endif 93 | 94 | if (pb) 95 | { 96 | /* scale pixbuf if needed */ 97 | w = gdk_pixbuf_get_width (pb); 98 | h = gdk_pixbuf_get_height (pb); 99 | if (w > size || h > size) 100 | { 101 | pb = gdk_pixbuf_scale_simple (spb, size, size, GDK_INTERP_BILINEAR); 102 | g_object_unref (spb); 103 | } 104 | } 105 | 106 | gtk_list_store_append (store, &iter); 107 | gtk_list_store_set (store, &iter, 0, pb, 1, i->data, -1); 108 | 109 | if (pb) 110 | g_object_unref (pb); 111 | } 112 | g_list_free_full (icons, g_free); 113 | 114 | gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), 1, GTK_SORT_ASCENDING); 115 | 116 | return store; 117 | } 118 | 119 | static void 120 | print_icon (GtkTreeView *tv, GtkTreePath *path, GtkTreeViewColumn *col, IconBrowserData *data) 121 | { 122 | GtkTreeModel *model; 123 | GtkTreeIter iter; 124 | gchar *icon; 125 | 126 | model = gtk_tree_view_get_model (tv); 127 | gtk_tree_model_get_iter (model, &iter, path); 128 | gtk_tree_model_get (model, &iter, 1, &icon, -1); 129 | 130 | g_print ("%s\n", icon); 131 | 132 | gtk_main_quit (); 133 | } 134 | 135 | static void 136 | select_icon (GtkTreeSelection * sel, IconBrowserData * data) 137 | { 138 | GtkTreeModel *model; 139 | GtkTreeIter iter; 140 | GtkIconInfo *info; 141 | gint *sz, i; 142 | gchar *icon, *file; 143 | GString *sizes; 144 | 145 | if (!gtk_tree_selection_get_selected (sel, &model, &iter)) 146 | return; 147 | 148 | gtk_tree_model_get (model, &iter, 1, &icon, -1); 149 | 150 | gtk_image_set_from_icon_name (GTK_IMAGE (data->image), icon, GTK_ICON_SIZE_DIALOG); 151 | 152 | sz = gtk_icon_theme_get_icon_sizes (data->theme, icon); 153 | info = gtk_icon_theme_lookup_icon (data->theme, icon, sz[0], 0); 154 | 155 | if (info) 156 | file = (gchar *) gtk_icon_info_get_filename (info); 157 | else 158 | file = NULL; 159 | 160 | /* create sizes string */ 161 | i = 0; 162 | sizes = g_string_new (""); 163 | while (sz[i]) 164 | { 165 | if (sz[i] == -1) 166 | g_string_append (sizes, _("scalable ")); 167 | else 168 | g_string_append_printf (sizes, "%dx%d ", sz[i], sz[i]); 169 | i++; 170 | } 171 | /* free memory */ 172 | g_free (sz); 173 | 174 | gtk_label_set_text (GTK_LABEL (data->lname), icon); 175 | gtk_label_set_text (GTK_LABEL (data->lsize), sizes->str); 176 | gtk_label_set_text (GTK_LABEL (data->lfile), file ? file : _("built-in")); 177 | 178 | g_string_free (sizes, TRUE); 179 | 180 | if (info) 181 | #if !GTK_CHECK_VERSION(3,0,0) 182 | gtk_icon_info_free(info); 183 | #else 184 | g_object_unref (info); 185 | #endif 186 | } 187 | 188 | static void 189 | select_cat (GtkTreeSelection * sel, IconBrowserData * data) 190 | { 191 | GtkTreeModel *model; 192 | GtkListStore *store; 193 | GtkTreeIter iter; 194 | gchar *cat; 195 | 196 | if (!gtk_tree_selection_get_selected (sel, &model, &iter)) 197 | return; 198 | 199 | gtk_tree_model_get (model, &iter, 0, &cat, -1); 200 | 201 | store = g_hash_table_lookup (data->icons, cat); 202 | if (!store) 203 | { 204 | store = load_icon_cat (data, cat); 205 | g_hash_table_insert (data->icons, cat, store); 206 | } 207 | gtk_tree_view_set_model (GTK_TREE_VIEW (data->icon_list), GTK_TREE_MODEL (store)); 208 | } 209 | 210 | gint 211 | main (gint argc, gchar * argv[]) 212 | { 213 | IconBrowserData *data; 214 | gchar **themes = NULL; 215 | GList *ic, *icat; 216 | GtkListStore *store; 217 | GtkTreeSelection *sel; 218 | GtkTreeViewColumn *col; 219 | GtkCellRenderer *r; 220 | GtkWidget *w, *p, *box, *t; 221 | gboolean ver = FALSE; 222 | gboolean all = FALSE, symbolic = FALSE, interactive = FALSE; 223 | 224 | GError *err = NULL; 225 | GOptionContext *ctx; 226 | 227 | GOptionEntry entrs[] = { 228 | { "version", 'v', 0, G_OPTION_ARG_NONE, &ver, N_("Print version"), NULL }, 229 | { "all", 'a', 0, G_OPTION_ARG_NONE, &all, _("Show all icons"), NULL }, 230 | { "symbolic", 's', 0, G_OPTION_ARG_NONE, &symbolic, _("Show only symbolic icons"), NULL }, 231 | { "interactive", 'i', 0, G_OPTION_ARG_NONE, &interactive, _("Select and print icon on double-click"), NULL }, 232 | { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &themes, NULL, NULL }, 233 | { NULL } 234 | }; 235 | 236 | data = g_new0 (IconBrowserData, 1); 237 | 238 | #ifdef ENABLE_NLS 239 | bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); 240 | bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); 241 | textdomain (GETTEXT_PACKAGE); 242 | #endif 243 | 244 | /* Parse the command line arguments */ 245 | ctx = g_option_context_new (_("- Icon browser")); 246 | g_option_context_set_ignore_unknown_options (ctx, TRUE); 247 | g_option_context_add_main_entries (ctx, entrs, GETTEXT_PACKAGE); 248 | g_option_context_add_group (ctx, gtk_get_option_group (TRUE)); 249 | if (!g_option_context_parse (ctx, &argc, &argv, &err)) 250 | { 251 | g_printerr ("Option parsing failed: %s\n", err->message); 252 | return 1; 253 | } 254 | 255 | data = g_new0 (IconBrowserData, 1); 256 | 257 | if (ver) 258 | { 259 | g_print ("%s (GTK+ %d.%d.%d)\n", PACKAGE_VERSION, gtk_major_version, gtk_minor_version, gtk_micro_version); 260 | return 0; 261 | } 262 | 263 | if (all) 264 | { 265 | show_regular = TRUE; 266 | show_symbolic = TRUE; 267 | } 268 | else if (symbolic) 269 | { 270 | show_regular = FALSE; 271 | show_symbolic = TRUE; 272 | } 273 | 274 | /* load icon theme */ 275 | data->theme = gtk_icon_theme_get_default (); 276 | if (themes && themes[0]) 277 | { 278 | data->theme = gtk_icon_theme_new (); 279 | gtk_icon_theme_set_custom_theme (data->theme, themes[0]); 280 | } 281 | 282 | /* create interface */ 283 | data->win = gtk_window_new (GTK_WINDOW_TOPLEVEL); 284 | gtk_window_set_title (GTK_WINDOW (data->win), _("Icon browser")); 285 | gtk_window_set_icon_name (GTK_WINDOW (data->win), "gtk-info"); 286 | gtk_window_set_default_size (GTK_WINDOW (data->win), 500, 400); 287 | g_signal_connect (G_OBJECT (data->win), "delete-event", G_CALLBACK (gtk_main_quit), NULL); 288 | g_signal_connect (G_OBJECT (data->win), "key-press-event", G_CALLBACK (key_press_cb), NULL); 289 | 290 | #if !GTK_CHECK_VERSION(3,0,0) 291 | box = gtk_vbox_new (FALSE, 5); 292 | #else 293 | box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); 294 | #endif 295 | gtk_container_add (GTK_CONTAINER (data->win), box); 296 | gtk_container_set_border_width (GTK_CONTAINER (data->win), 5); 297 | 298 | /* create icon info box */ 299 | #if !GTK_CHECK_VERSION(3,0,0) 300 | t = gtk_table_new (3, 3, FALSE); 301 | gtk_table_set_col_spacings (GTK_TABLE (t), 5); 302 | gtk_table_set_row_spacings (GTK_TABLE (t), 5); 303 | #else 304 | t = gtk_grid_new (); 305 | gtk_grid_set_row_spacing (GTK_GRID (t), 5); 306 | gtk_grid_set_column_spacing (GTK_GRID (t), 5); 307 | #endif 308 | gtk_box_pack_start (GTK_BOX (box), t, FALSE, FALSE, 2); 309 | 310 | data->image = gtk_image_new_from_icon_name ("image-missing", GTK_ICON_SIZE_DIALOG); 311 | #if !GTK_CHECK_VERSION(3,0,0) 312 | gtk_table_attach (GTK_TABLE (t), data->image, 0, 1, 0, 3, GTK_FILL, 0, 0, 0); 313 | #else 314 | gtk_grid_attach (GTK_GRID (t), data->image, 0, 0, 1, 3); 315 | #endif 316 | 317 | w = gtk_label_new (NULL); 318 | gtk_label_set_markup (GTK_LABEL (w), _("Name:")); 319 | #if !GTK_CHECK_VERSION(3,0,0) 320 | gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); 321 | gtk_table_attach (GTK_TABLE (t), w, 1, 2, 0, 1, GTK_FILL, 0, 0, 0); 322 | #else 323 | gtk_label_set_xalign (GTK_LABEL (w), 0.0); 324 | gtk_grid_attach (GTK_GRID (t), w, 1, 0, 1, 1); 325 | #endif 326 | data->lname = gtk_label_new (NULL); 327 | gtk_label_set_selectable (GTK_LABEL (data->lname), TRUE); 328 | #if !GTK_CHECK_VERSION(3,0,0) 329 | gtk_misc_set_alignment (GTK_MISC (data->lname), 0.0, 0.5); 330 | gtk_table_attach (GTK_TABLE (t), data->lname, 2, 3, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); 331 | #else 332 | gtk_label_set_xalign (GTK_LABEL (data->lname), 0.0); 333 | gtk_grid_attach (GTK_GRID (t), data->lname, 2, 0, 1, 1); 334 | gtk_widget_set_hexpand (data->lname, TRUE); 335 | #endif 336 | 337 | w = gtk_label_new (NULL); 338 | gtk_label_set_markup (GTK_LABEL (w), _("Sizes:")); 339 | #if !GTK_CHECK_VERSION(3,0,0) 340 | gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); 341 | gtk_table_attach (GTK_TABLE (t), w, 1, 2, 1, 2, GTK_FILL, 0, 0, 0); 342 | #else 343 | gtk_label_set_xalign (GTK_LABEL (w), 0.0); 344 | gtk_grid_attach (GTK_GRID (t), w, 1, 1, 1, 1); 345 | #endif 346 | data->lsize = gtk_label_new (NULL); 347 | gtk_label_set_selectable (GTK_LABEL (data->lsize), TRUE); 348 | #if !GTK_CHECK_VERSION(3,0,0) 349 | gtk_misc_set_alignment (GTK_MISC (data->lsize), 0.0, 0.5); 350 | gtk_table_attach (GTK_TABLE (t), data->lsize, 2, 3, 1, 2, GTK_FILL | GTK_EXPAND, 0, 0, 0); 351 | #else 352 | gtk_label_set_xalign (GTK_LABEL (data->lsize), 0.0); 353 | gtk_grid_attach (GTK_GRID (t), data->lsize, 2, 1, 1, 1); 354 | gtk_widget_set_hexpand (data->lsize, TRUE); 355 | #endif 356 | 357 | w = gtk_label_new (NULL); 358 | gtk_label_set_markup (GTK_LABEL (w), _("Filename:")); 359 | #if !GTK_CHECK_VERSION(3,0,0) 360 | gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5); 361 | gtk_table_attach (GTK_TABLE (t), w, 1, 2, 2, 3, GTK_FILL, 0, 0, 0); 362 | #else 363 | gtk_label_set_xalign (GTK_LABEL (w), 0.0); 364 | gtk_grid_attach (GTK_GRID (t), w, 1, 2, 1, 1); 365 | #endif 366 | data->lfile = gtk_label_new (NULL); 367 | gtk_label_set_selectable (GTK_LABEL (data->lfile), TRUE); 368 | #if !GTK_CHECK_VERSION(3,0,0) 369 | gtk_misc_set_alignment (GTK_MISC (data->lfile), 0.0, 0.5); 370 | gtk_table_attach (GTK_TABLE (t), data->lfile, 2, 3, 2, 3, GTK_FILL | GTK_EXPAND, 0, 0, 0); 371 | #else 372 | gtk_label_set_xalign (GTK_LABEL (data->lfile), 0.0); 373 | gtk_grid_attach (GTK_GRID (t), data->lfile, 2, 2, 1, 1); 374 | gtk_widget_set_hexpand (data->lfile, TRUE); 375 | #endif 376 | 377 | /* create icon browser */ 378 | #if !GTK_CHECK_VERSION(3,0,0) 379 | p = gtk_hpaned_new (); 380 | #else 381 | p = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL); 382 | #endif 383 | gtk_paned_set_position (GTK_PANED (p), 150); 384 | gtk_box_pack_start (GTK_BOX (box), p, TRUE, TRUE, 2); 385 | 386 | /* create category list */ 387 | w = gtk_scrolled_window_new (NULL, NULL); 388 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 389 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_ETCHED_IN); 390 | gtk_paned_add1 (GTK_PANED (p), w); 391 | 392 | store = gtk_list_store_new (1, G_TYPE_STRING); 393 | 394 | data->cat_list = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); 395 | gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (data->cat_list), TRUE); 396 | gtk_container_add (GTK_CONTAINER (w), data->cat_list); 397 | 398 | sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->cat_list)); 399 | g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (select_cat), data); 400 | 401 | r = gtk_cell_renderer_text_new (); 402 | col = gtk_tree_view_column_new_with_attributes (_("Category"), r, "text", 0, NULL); 403 | gtk_tree_view_column_set_expand (col, TRUE); 404 | gtk_tree_view_append_column (GTK_TREE_VIEW (data->cat_list), col); 405 | 406 | /* load icons category */ 407 | data->icons = g_hash_table_new (g_direct_hash, g_direct_equal); 408 | icat = gtk_icon_theme_list_contexts (data->theme); 409 | for (ic = icat; ic; ic = ic->next) 410 | { 411 | GtkTreeIter iter; 412 | 413 | gtk_list_store_append (store, &iter); 414 | gtk_list_store_set (store, &iter, 0, ic->data, -1); 415 | g_free (ic->data); 416 | } 417 | g_list_free (icat); 418 | 419 | /* create icons list */ 420 | w = gtk_scrolled_window_new (NULL, NULL); 421 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 422 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_ETCHED_IN); 423 | gtk_paned_add2 (GTK_PANED (p), w); 424 | 425 | data->icon_list = gtk_tree_view_new (); 426 | gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (data->icon_list), TRUE); 427 | #if !GTK_CHECK_VERSION(3,0,0) 428 | gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (data->icon_list), TRUE); 429 | #endif 430 | gtk_container_add (GTK_CONTAINER (w), data->icon_list); 431 | 432 | sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (data->icon_list)); 433 | g_signal_connect (G_OBJECT (sel), "changed", G_CALLBACK (select_icon), data); 434 | 435 | if (interactive) 436 | g_signal_connect (G_OBJECT (data->icon_list), "row-activated", G_CALLBACK (print_icon), data); 437 | 438 | col = gtk_tree_view_column_new (); 439 | gtk_tree_view_column_set_title (col, _("Icons")); 440 | gtk_tree_view_column_set_sort_column_id (col, 1); 441 | r = gtk_cell_renderer_pixbuf_new (); 442 | gtk_tree_view_column_pack_start (col, r, FALSE); 443 | gtk_tree_view_column_set_attributes (col, r, "pixbuf", 0, NULL); 444 | r = gtk_cell_renderer_text_new (); 445 | gtk_tree_view_column_pack_start (col, r, FALSE); 446 | gtk_tree_view_column_set_attributes (col, r, "text", 1, NULL); 447 | gtk_tree_view_column_set_expand (col, TRUE); 448 | gtk_tree_view_append_column (GTK_TREE_VIEW (data->icon_list), col); 449 | 450 | gtk_widget_show_all (data->win); 451 | 452 | /* run it */ 453 | gtk_main (); 454 | 455 | return 0; 456 | } 457 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | #include "yad.h" 28 | 29 | #define HEADER_HEIGHT (10*72/25.4) 30 | #define HEADER_GAP (3*72/25.4) 31 | #define HEADER_FONT "Sans 11" 32 | 33 | #define FONTNAME "Monospace" 34 | #define FONTSIZE 11.0 35 | 36 | static gchar **text; 37 | static gint nlines, npages; 38 | 39 | static PangoFontDescription *fdesc = NULL; 40 | 41 | static void 42 | draw_header (GtkPrintContext * cnt, gint pn, gint pc) 43 | { 44 | cairo_t *cr; 45 | PangoFontDescription *desc; 46 | PangoLayout *layout; 47 | gint pw, tw, th; 48 | gchar *page; 49 | 50 | cr = gtk_print_context_get_cairo_context (cnt); 51 | pw = gtk_print_context_get_width (cnt); 52 | 53 | layout = gtk_print_context_create_pango_layout (cnt); 54 | 55 | desc = pango_font_description_from_string (HEADER_FONT); 56 | pango_layout_set_font_description (layout, desc); 57 | pango_font_description_free (desc); 58 | 59 | pango_layout_set_text (layout, options.common_data.uri, -1); 60 | pango_layout_get_pixel_size (layout, &tw, &th); 61 | if (tw > pw) 62 | { 63 | pango_layout_set_width (layout, pw); 64 | pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_START); 65 | pango_layout_get_pixel_size (layout, &tw, &th); 66 | } 67 | 68 | cairo_move_to (cr, (pw - tw) / 2, (HEADER_HEIGHT - th) / 2); 69 | pango_cairo_show_layout (cr, layout); 70 | 71 | page = g_strdup_printf ("%d/%d", pn, pc); 72 | pango_layout_set_text (layout, page, -1); 73 | g_free (page); 74 | 75 | pango_layout_set_width (layout, -1); 76 | pango_layout_get_pixel_size (layout, &tw, &th); 77 | cairo_move_to (cr, pw - tw - 4, (HEADER_HEIGHT - th) / 2); 78 | pango_cairo_show_layout (cr, layout); 79 | 80 | g_object_unref (layout); 81 | 82 | cairo_move_to (cr, 0.0, HEADER_HEIGHT); 83 | cairo_line_to (cr, pw, HEADER_HEIGHT); 84 | 85 | cairo_set_source_rgb (cr, 0, 0, 0); 86 | cairo_set_line_width (cr, 1); 87 | cairo_stroke (cr); 88 | } 89 | 90 | static void 91 | begin_print_text (GtkPrintOperation * op, GtkPrintContext * cnt, gpointer data) 92 | { 93 | gchar *buf; 94 | gint i = 0; 95 | gdouble ph; 96 | 97 | /* load file */ 98 | g_file_get_contents (options.common_data.uri, &buf, NULL, NULL); 99 | text = g_strsplit (buf, "\n", 0); 100 | g_free (buf); 101 | 102 | while (text[i] != NULL) 103 | i++; 104 | 105 | ph = gtk_print_context_get_height (cnt); 106 | if (options.print_data.headers) 107 | ph -= HEADER_HEIGHT + HEADER_GAP; 108 | 109 | nlines = ph / FONTSIZE; 110 | npages = i / nlines + 1; 111 | gtk_print_operation_set_n_pages (op, npages); 112 | 113 | /* set font */ 114 | if (options.common_data.font) 115 | fdesc = pango_font_description_from_string (options.common_data.font); 116 | else 117 | { 118 | fdesc = pango_font_description_from_string (FONTNAME); 119 | pango_font_description_set_size (fdesc, FONTSIZE * PANGO_SCALE); 120 | } 121 | } 122 | 123 | static void 124 | draw_page_text (GtkPrintOperation * op, GtkPrintContext * cnt, gint page, gpointer data) 125 | { 126 | cairo_t *cr; 127 | PangoLayout *layout; 128 | gint i, line; 129 | 130 | cr = gtk_print_context_get_cairo_context (cnt); 131 | 132 | /* create header */ 133 | if (options.print_data.headers) 134 | draw_header (cnt, page + 1, npages); 135 | 136 | /* add text */ 137 | layout = gtk_print_context_create_pango_layout (cnt); 138 | pango_layout_set_font_description (layout, fdesc); 139 | 140 | cairo_move_to (cr, 0, HEADER_HEIGHT + HEADER_GAP); 141 | 142 | line = page * nlines; 143 | for (i = 0; i < nlines; i++) 144 | { 145 | if (text[line + i] == NULL) 146 | break; 147 | pango_layout_set_text (layout, text[line + i], -1); 148 | pango_cairo_show_layout (cr, layout); 149 | cairo_rel_move_to (cr, 0, FONTSIZE); 150 | } 151 | 152 | g_object_unref (layout); 153 | } 154 | 155 | static void 156 | draw_page_image (GtkPrintOperation * op, GtkPrintContext * cnt, gint page, gpointer data) 157 | { 158 | cairo_t *cr; 159 | GdkPixbuf *pb, *spb; 160 | guint iw, ih; 161 | gdouble pw, ph; 162 | gdouble factor; 163 | 164 | cr = gtk_print_context_get_cairo_context (cnt); 165 | 166 | pw = gtk_print_context_get_width (cnt); 167 | ph = gtk_print_context_get_height (cnt); 168 | 169 | /* create header */ 170 | if (options.print_data.headers) 171 | { 172 | ph -= HEADER_HEIGHT + HEADER_GAP; 173 | draw_header (cnt, 1, 1); 174 | } 175 | 176 | /* scale image to page size */ 177 | pb = gdk_pixbuf_new_from_file (options.common_data.uri, NULL); 178 | iw = gdk_pixbuf_get_width (pb); 179 | ih = gdk_pixbuf_get_height (pb); 180 | 181 | if (pw < iw || ph < ih) 182 | { 183 | factor = MIN (pw / iw, ph / ih); 184 | factor = (factor > 1.0) ? 1.0 : factor; 185 | spb = gdk_pixbuf_scale_simple (pb, iw * factor, ih * factor, GDK_INTERP_HYPER); 186 | } 187 | else 188 | spb = g_object_ref (pb); 189 | g_object_unref (pb); 190 | 191 | /* add image to surface */ 192 | gdk_cairo_set_source_pixbuf (cr, spb, 0.0, HEADER_HEIGHT + HEADER_GAP); 193 | cairo_paint (cr); 194 | g_object_unref (spb); 195 | } 196 | 197 | static void 198 | raw_print_done (GtkPrintJob * job, gint * ret, GError * err) 199 | { 200 | if (err) 201 | { 202 | g_printerr (_("Printing failed: %s\n"), err->message); 203 | *ret = 1; 204 | } 205 | yad_exit (options.data.def_resp); 206 | } 207 | 208 | static void 209 | size_allocate_cb (GtkWidget * w, GtkAllocation * al, gpointer data) 210 | { 211 | gtk_widget_set_size_request (w, al->width, -1); 212 | } 213 | 214 | static gboolean 215 | save_settings (GtkPrintSettings *print_settings, GtkPageSetup *page_setup) 216 | { 217 | GKeyFile *kf; 218 | gchar *fn, *contents; 219 | gboolean res = 0; 220 | 221 | kf = g_key_file_new (); 222 | 223 | if (print_settings) 224 | gtk_print_settings_to_key_file (print_settings, kf, NULL); 225 | 226 | if (page_setup) 227 | gtk_page_setup_to_key_file (page_setup, kf, NULL); 228 | 229 | contents = g_key_file_to_data (kf, NULL, NULL); 230 | g_key_file_free (kf); 231 | 232 | fn = g_build_filename (g_get_user_config_dir (), "yad", NULL); 233 | g_mkdir_with_parents (fn, 0700); 234 | g_free (fn); 235 | 236 | fn = g_build_filename (g_get_user_config_dir (), "yad", "print.conf", NULL); 237 | res = g_file_set_contents (fn, contents, -1, NULL); 238 | g_free (fn); 239 | g_free (contents); 240 | 241 | if (!res) 242 | g_printerr (_("Cannot save print settings file: %s\n"), strerror (errno)); 243 | 244 | return res; 245 | } 246 | 247 | gint 248 | yad_print_run (void) 249 | { 250 | GtkWidget *dlg; 251 | GtkWidget *box, *img, *lbl; 252 | gchar *uri, *fn, *job_name = NULL; 253 | GtkPrintCapabilities pcap; 254 | GtkPrintOperationAction act = GTK_PRINT_OPERATION_ACTION_PRINT; 255 | GtkPrintSettings *print_settings = NULL; 256 | GtkPageSetup *page_setup = NULL; 257 | gint resp, ret = 0; 258 | GError *err = NULL; 259 | 260 | /* check if file is exists */ 261 | if (options.common_data.uri && options.common_data.uri[0]) 262 | { 263 | if (!g_file_test (options.common_data.uri, G_FILE_TEST_EXISTS)) 264 | { 265 | g_printerr (_("File %s not found.\n"), options.common_data.uri); 266 | return 1; 267 | } 268 | } 269 | else 270 | { 271 | g_printerr (_("Filename is not specified.\n")); 272 | return 1; 273 | } 274 | 275 | /* load previously saved print settings */ 276 | fn = g_build_filename (g_get_user_config_dir (), "yad", "print.conf", NULL); 277 | if (g_file_test (fn, G_FILE_TEST_EXISTS)) 278 | { 279 | print_settings = gtk_print_settings_new_from_file (fn, NULL); 280 | page_setup = gtk_page_setup_new_from_file (fn, NULL); 281 | } 282 | g_free (fn); 283 | 284 | if (!print_settings) 285 | print_settings = gtk_print_settings_new (); 286 | if (!page_setup) 287 | page_setup = gtk_page_setup_new (); 288 | 289 | /* create print dialog */ 290 | dlg = gtk_print_unix_dialog_new (options.data.dialog_title, NULL); 291 | gtk_window_set_type_hint (GTK_WINDOW (dlg), GDK_WINDOW_TYPE_HINT_NORMAL); 292 | gtk_print_unix_dialog_set_embed_page_setup (GTK_PRINT_UNIX_DIALOG (dlg), TRUE); 293 | pcap = GTK_PRINT_CAPABILITY_PAGE_SET | GTK_PRINT_CAPABILITY_COPIES | 294 | GTK_PRINT_CAPABILITY_COLLATE | GTK_PRINT_CAPABILITY_REVERSE | 295 | GTK_PRINT_CAPABILITY_NUMBER_UP | GTK_PRINT_CAPABILITY_NUMBER_UP_LAYOUT; 296 | if (options.common_data.preview && options.print_data.type != YAD_PRINT_RAW) 297 | pcap |= GTK_PRINT_CAPABILITY_PREVIEW; 298 | gtk_print_unix_dialog_set_manual_capabilities (GTK_PRINT_UNIX_DIALOG (dlg), pcap); 299 | 300 | uri = (gchar *) gtk_print_settings_get(print_settings, "output-uri"); 301 | if (uri == NULL) 302 | { 303 | uri = g_build_filename (g_get_current_dir (), "yad.pdf", NULL); 304 | gtk_print_settings_set (print_settings, "output-uri", g_filename_to_uri (uri, NULL, NULL)); 305 | g_free (uri); 306 | } 307 | 308 | gtk_print_unix_dialog_set_settings (GTK_PRINT_UNIX_DIALOG (dlg), print_settings); 309 | gtk_print_unix_dialog_set_page_setup (GTK_PRINT_UNIX_DIALOG (dlg), page_setup); 310 | 311 | /* set window behavior */ 312 | gtk_widget_set_name (dlg, "yad-dialog-window"); 313 | if (options.data.sticky) 314 | gtk_window_stick (GTK_WINDOW (dlg)); 315 | gtk_window_set_resizable (GTK_WINDOW (dlg), !options.data.fixed); 316 | gtk_window_set_keep_above (GTK_WINDOW (dlg), options.data.ontop); 317 | gtk_window_set_decorated (GTK_WINDOW (dlg), !options.data.undecorated); 318 | gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dlg), options.data.skip_taskbar); 319 | gtk_window_set_skip_pager_hint (GTK_WINDOW (dlg), options.data.skip_taskbar); 320 | 321 | /* set window size and position */ 322 | gtk_window_set_default_size (GTK_WINDOW (dlg), options.data.width, options.data.height); 323 | if (options.data.center) 324 | gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_CENTER); 325 | else if (options.data.mouse) 326 | gtk_window_set_position (GTK_WINDOW (dlg), GTK_WIN_POS_MOUSE); 327 | 328 | /* create yad's top box */ 329 | if (options.data.dialog_text || options.data.dialog_image) 330 | { 331 | #if !GTK_CHECK_VERSION(3,0,0) 332 | box = gtk_hbox_new (FALSE, 0); 333 | #else 334 | box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); 335 | #endif 336 | 337 | if (options.data.dialog_image) 338 | { 339 | GdkPixbuf *pb = NULL; 340 | 341 | pb = get_pixbuf (options.data.dialog_image, YAD_BIG_ICON, FALSE); 342 | img = gtk_image_new_from_pixbuf (pb); 343 | if (pb) 344 | g_object_unref (pb); 345 | 346 | gtk_widget_set_name (img, "yad-dialog-image"); 347 | gtk_box_pack_start (GTK_BOX (box), img, FALSE, FALSE, 2); 348 | } 349 | if (options.data.dialog_text) 350 | { 351 | gchar *buf = g_strcompress (options.data.dialog_text); 352 | 353 | lbl = gtk_label_new (NULL); 354 | if (!options.data.no_markup) 355 | gtk_label_set_markup (GTK_LABEL (lbl), buf); 356 | else 357 | gtk_label_set_text (GTK_LABEL (lbl), buf); 358 | gtk_widget_set_name (lbl, "yad-dialog-label"); 359 | gtk_label_set_selectable (GTK_LABEL (lbl), options.data.selectable_labels); 360 | #if !GTK_CHECK_VERSION(3,0,0) 361 | gtk_misc_set_alignment (GTK_MISC (lbl), options.data.text_align, 0.5); 362 | #else 363 | gtk_label_set_xalign (GTK_LABEL (lbl), options.data.text_align); 364 | #endif 365 | if (options.data.geometry || options.data.width != -1) 366 | gtk_label_set_line_wrap (GTK_LABEL (lbl), TRUE); 367 | gtk_box_pack_start (GTK_BOX (box), lbl, TRUE, TRUE, 2); 368 | g_signal_connect (G_OBJECT (lbl), "size-allocate", G_CALLBACK (size_allocate_cb), NULL); 369 | g_free (buf); 370 | } 371 | 372 | /* add tob box to dialog */ 373 | gtk_widget_show_all (box); 374 | gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), box, TRUE, TRUE, 5); 375 | gtk_box_reorder_child (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dlg))), box, 0); 376 | } 377 | 378 | do 379 | { 380 | resp = gtk_dialog_run (GTK_DIALOG (dlg)); 381 | switch (resp) 382 | { 383 | case GTK_RESPONSE_APPLY: /* ask for preview */ 384 | act = GTK_PRINT_OPERATION_ACTION_PREVIEW; 385 | case GTK_RESPONSE_OK: /* run print */ 386 | print_settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (dlg)); 387 | page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (dlg)); 388 | job_name = g_strdup_printf ("yad-%s-%d", g_path_get_basename (options.common_data.uri), getpid ()); 389 | if (options.print_data.type != YAD_PRINT_RAW) 390 | { 391 | /* print text or image */ 392 | GtkPrintOperation *op = gtk_print_operation_new (); 393 | gtk_print_operation_set_unit (op, GTK_UNIT_POINTS); 394 | gtk_print_operation_set_print_settings (op, print_settings); 395 | gtk_print_operation_set_default_page_setup (op, page_setup); 396 | gtk_print_operation_set_job_name (op, job_name); 397 | 398 | switch (options.print_data.type) 399 | { 400 | case YAD_PRINT_TEXT: 401 | g_signal_connect (G_OBJECT (op), "begin-print", G_CALLBACK (begin_print_text), NULL); 402 | g_signal_connect (G_OBJECT (op), "draw-page", G_CALLBACK (draw_page_text), NULL); 403 | break; 404 | case YAD_PRINT_IMAGE: 405 | gtk_print_operation_set_n_pages (op, 1); 406 | g_signal_connect (G_OBJECT (op), "draw-page", G_CALLBACK (draw_page_image), NULL); 407 | break; 408 | default:; 409 | } 410 | 411 | if (gtk_print_operation_run (op, act, NULL, &err) == GTK_PRINT_OPERATION_RESULT_ERROR) 412 | { 413 | g_printerr (_("Printing failed: %s\n"), err->message); 414 | ret = 1; 415 | } 416 | 417 | /* for a CUPS printer op could display another print settings/page setup dialog */ 418 | print_settings = gtk_print_operation_get_print_settings (op); 419 | page_setup = gtk_print_operation_get_default_page_setup (op); 420 | } 421 | else 422 | { 423 | /* print raw ps or pdf data */ 424 | GtkPrinter *prnt; 425 | GtkPrintJob *job; 426 | 427 | prnt = gtk_print_unix_dialog_get_selected_printer (GTK_PRINT_UNIX_DIALOG (dlg)); 428 | 429 | if (g_str_has_suffix (options.common_data.uri, ".ps")) 430 | { 431 | if (!gtk_printer_accepts_ps (prnt)) 432 | { 433 | g_printerr (_("Printer doesn't support ps format.\n")); 434 | ret = 1; 435 | } 436 | } 437 | else if (g_str_has_suffix (options.common_data.uri, ".pdf")) 438 | { 439 | if (!gtk_printer_accepts_pdf (prnt)) 440 | { 441 | g_printerr (_("Printer doesn't support pdf format.\n")); 442 | ret = 1; 443 | } 444 | } 445 | else 446 | { 447 | g_printerr (_("This file type is not supported for raw printing.\n")); 448 | ret = 1; 449 | } 450 | if (ret == 1) 451 | break; 452 | 453 | job = gtk_print_job_new (job_name, prnt, print_settings, page_setup); 454 | if (gtk_print_job_set_source_file (job, options.common_data.uri, &err)) 455 | { 456 | gtk_print_job_send (job, (GtkPrintJobCompleteFunc) raw_print_done, &ret, NULL); 457 | gtk_main (); 458 | } 459 | else 460 | { 461 | g_printerr (_("Load source file failed: %s\n"), err->message); 462 | ret = 1; 463 | } 464 | } 465 | break; 466 | default: 467 | ret = 1; 468 | break; 469 | } 470 | } 471 | while (resp == GTK_RESPONSE_APPLY); 472 | 473 | gtk_widget_destroy (dlg); 474 | 475 | if (0 == ret) 476 | ret = ! save_settings(print_settings, page_setup); 477 | 478 | return ret; 479 | } 480 | -------------------------------------------------------------------------------- /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-2019, Victor Ananjevsky 18 | * Copyright (C) 2019-2025, step https://github.com/step- 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "yad.h" 29 | 30 | static GSList *progress_bars = NULL; 31 | static guint nbars = 0; 32 | 33 | static GtkWidget *progress_log; 34 | static GtkTextBuffer *log_buffer; 35 | 36 | static gboolean single_mode = FALSE; 37 | 38 | static gboolean 39 | pulsate_progress_bar (GtkProgressBar *bar) 40 | { 41 | gtk_progress_bar_pulse (bar); 42 | return TRUE; 43 | } 44 | 45 | static gboolean 46 | handle_stdin (GIOChannel *channel, GIOCondition condition, gpointer data) 47 | { 48 | static guint single_mode_pulsate_timeout = 0; 49 | float percentage = 0.0; 50 | 51 | if ((condition == G_IO_IN) || (condition == G_IO_IN + G_IO_HUP)) 52 | { 53 | GString *string; 54 | gchar **value; 55 | GError *err = NULL; 56 | 57 | string = g_string_new (NULL); 58 | 59 | while (channel->is_readable != TRUE) 60 | usleep (100); 61 | 62 | do 63 | { 64 | gint status, num; 65 | GtkProgressBar *pb; 66 | YadProgressBar *b; 67 | 68 | do 69 | { 70 | status = g_io_channel_read_line_string (channel, string, NULL, &err); 71 | 72 | while (gtk_events_pending ()) 73 | gtk_main_iteration (); 74 | } 75 | while (status == G_IO_STATUS_AGAIN); 76 | 77 | if (status != G_IO_STATUS_NORMAL) 78 | { 79 | if (err) 80 | { 81 | g_printerr ("yad_multi_progress_handle_stdin(): %s\n", err->message); 82 | g_error_free (err); 83 | err = NULL; 84 | } 85 | /* stop handling */ 86 | g_io_channel_shutdown (channel, TRUE, NULL); 87 | return FALSE; 88 | } 89 | 90 | if (single_mode) 91 | { 92 | value = g_new0 (gchar *, 2); 93 | value[1] = g_strdup (string->str); 94 | num = 0; 95 | } 96 | else 97 | { 98 | value = g_strsplit (string->str, ":", 2); 99 | num = atoi (value[0]) - 1; 100 | if (num < 0 || num > nbars - 1) 101 | continue; 102 | } 103 | 104 | pb = GTK_PROGRESS_BAR (g_slist_nth_data (progress_bars, num)); 105 | b = (YadProgressBar *) g_slist_nth_data (options.progress_data.bars, num); 106 | 107 | if (value[1] && value[1][0] == '#') 108 | { 109 | gchar *match; 110 | 111 | /* We have a comment, so let's try to change the label */ 112 | match = g_strcompress (value[1] + 1); 113 | strip_new_line (match); 114 | if (options.progress_data.log) 115 | { 116 | gchar *logline; 117 | GtkTextIter end; 118 | 119 | logline = g_strdup_printf ("%s\n", match); /* add new line */ 120 | gtk_text_buffer_get_end_iter (log_buffer, &end); 121 | gtk_text_buffer_insert (log_buffer, &end, logline, -1); 122 | g_free (logline); 123 | 124 | /* scroll to end */ 125 | while (gtk_events_pending ()) 126 | gtk_main_iteration (); 127 | gtk_text_buffer_get_end_iter (log_buffer, &end); 128 | gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (progress_log), &end, 0, FALSE, 0, 0); 129 | } 130 | else 131 | { 132 | if (!options.common_data.hide_text) 133 | gtk_progress_bar_set_text (pb, match); 134 | } 135 | g_free (match); 136 | } 137 | else 138 | { 139 | if (options.progress_data.pulsate && value[1] && b->type == YAD_PROGRESS_PULSE) 140 | { 141 | if (single_mode_pulsate_timeout == 0) 142 | single_mode_pulsate_timeout = g_timeout_add (100, (GSourceFunc) pulsate_progress_bar, pb); 143 | gtk_progress_bar_pulse (pb); 144 | } 145 | else if (value[1] && b->type == YAD_PROGRESS_PULSE) 146 | gtk_progress_bar_pulse (pb); 147 | else if (value[1] && b->type == YAD_PROGRESS_PERM) 148 | { 149 | guint id; 150 | 151 | if (strncmp (value[1], "start", 5) == 0) 152 | { 153 | id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pb), "id")); 154 | if (id == 0) 155 | { 156 | id = g_timeout_add (100, (GSourceFunc) pulsate_progress_bar, pb); 157 | g_object_set_data (G_OBJECT (pb), "id", GINT_TO_POINTER (id)); 158 | } 159 | } 160 | else if (strncmp (value[1], "stop", 4) == 0) 161 | { 162 | id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pb), "id")); 163 | if (id > 0) 164 | { 165 | g_source_remove (id); 166 | g_object_set_data (G_OBJECT (pb), "id", GINT_TO_POINTER (0)); 167 | } 168 | } 169 | } 170 | 171 | /* step: in version 0.42.x single-progress pulsate can set its percentange, 172 | which is desirable to be able to --auto-close the dialog at 100%. There is no 173 | harm to also let multi-progress PERM and PULSE bars set their percentage. */ 174 | /*{*/ 175 | if (!value[1] || !g_ascii_isdigit (*value[1])) 176 | continue; 177 | 178 | /* Now try to convert the thing to a number */ 179 | percentage = atoi (value[1]); 180 | if (percentage >= 100) 181 | gtk_progress_bar_set_fraction (pb, 1.0); 182 | else 183 | gtk_progress_bar_set_fraction (pb, percentage / 100.0); 184 | 185 | /* Check if all of progress bars reaches 100% */ 186 | if (options.progress_data.autoclose && options.plug == -1) 187 | { 188 | guint i; 189 | gboolean close = TRUE; 190 | gboolean need_close = FALSE; 191 | 192 | if (options.progress_data.watch_bar > 0 && options.progress_data.watch_bar <= nbars) 193 | { 194 | GtkProgressBar *cpb = GTK_PROGRESS_BAR (g_slist_nth_data (progress_bars, 195 | options.progress_data.watch_bar - 1)); 196 | 197 | need_close = TRUE; 198 | if (gtk_progress_bar_get_fraction (cpb) != 1.0) 199 | close = FALSE; 200 | } 201 | else 202 | { 203 | for (i = 0; i < nbars; i++) 204 | { 205 | GtkProgressBar *cpb = GTK_PROGRESS_BAR (g_slist_nth_data (progress_bars, i)); 206 | YadProgressBar *cb = (YadProgressBar *) g_slist_nth_data (options.progress_data.bars, i); 207 | 208 | if (cb->type != YAD_PROGRESS_PULSE) 209 | { 210 | need_close = TRUE; 211 | if (gtk_progress_bar_get_fraction (cpb) != 1.0) 212 | { 213 | close = FALSE; 214 | break; 215 | } 216 | } 217 | } 218 | } 219 | 220 | if (need_close && close) 221 | yad_exit (options.data.def_resp); 222 | } 223 | /*}*/ 224 | } 225 | } 226 | while (g_io_channel_get_buffer_condition (channel) == G_IO_IN); 227 | g_string_free (string, TRUE); 228 | } 229 | 230 | if ((condition != G_IO_IN) && (condition != G_IO_IN + G_IO_HUP)) 231 | { 232 | g_io_channel_shutdown (channel, TRUE, NULL); 233 | 234 | if (options.progress_data.autoclose && options.plug == -1) 235 | yad_exit (options.data.def_resp); 236 | 237 | return FALSE; 238 | } 239 | return TRUE; 240 | } 241 | 242 | GtkWidget * 243 | progress_create_widget (GtkWidget *dlg) 244 | { 245 | GtkWidget *table, *w = NULL; 246 | GIOChannel *channel; 247 | GSList *b; 248 | gint i = 0; 249 | 250 | nbars = g_slist_length (options.progress_data.bars); 251 | if (nbars < 1) 252 | { 253 | YadProgressBar *bar = g_new0 (YadProgressBar, 1); 254 | 255 | if (options.debug) 256 | g_printerr (_("WARNING: the old-style progress dialog option is deprecated: use --bar style instead\n")); 257 | 258 | if (options.progress_data.pulsate) 259 | bar->type = YAD_PROGRESS_PULSE; 260 | else if (options.progress_data.rtl) 261 | bar->type = YAD_PROGRESS_RTL; 262 | else 263 | bar->type = YAD_PROGRESS_NORMAL; 264 | 265 | #if GTK_CHECK_VERSION(3,0,0) 266 | /* #else handled in "maintain-gtk2" further down */ 267 | /* writes a fixed label on the side of the bar */ 268 | if (options.progress_data.progress_text) 269 | bar->name = options.progress_data.progress_text; 270 | #endif 271 | 272 | options.progress_data.bars = g_slist_append (options.progress_data.bars, bar); 273 | nbars = 1; 274 | 275 | options.progress_data.watch_bar = 1; 276 | 277 | single_mode = TRUE; 278 | } 279 | 280 | #if !GTK_CHECK_VERSION(3,0,0) 281 | if (options.common_data.vertical) 282 | table = gtk_table_new (2, nbars, FALSE); 283 | else 284 | table = gtk_table_new (nbars, 2, FALSE); 285 | #else 286 | table = gtk_grid_new (); 287 | gtk_grid_set_row_spacing (GTK_GRID (table), 2); 288 | gtk_grid_set_column_spacing (GTK_GRID (table), 2); 289 | #endif 290 | if (options.common_data.scroll) 291 | { 292 | GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL); 293 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_NONE); 294 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.data.hscroll_policy, options.data.vscroll_policy); 295 | #if !GTK_CHECK_VERSION(3,0,0) 296 | gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), table); 297 | #else 298 | gtk_container_add (GTK_CONTAINER (sw), table); 299 | #endif 300 | w = sw; 301 | } 302 | else 303 | w = table; 304 | 305 | for (b = options.progress_data.bars; b; b = b->next) 306 | { 307 | GtkWidget *l, *w; 308 | YadProgressBar *p = (YadProgressBar *) b->data; 309 | 310 | /* add label */ 311 | l = gtk_label_new (NULL); 312 | if (options.data.no_markup) 313 | gtk_label_set_text (GTK_LABEL (l), p->name); 314 | else 315 | gtk_label_set_markup (GTK_LABEL (l), p->name); 316 | #if !GTK_CHECK_VERSION(3,0,0) 317 | gtk_misc_set_alignment (GTK_MISC (l), options.common_data.align, 0.5); 318 | #else 319 | gtk_label_set_xalign (GTK_LABEL (l), options.common_data.align); 320 | #endif 321 | if (options.common_data.vertical) 322 | #if !GTK_CHECK_VERSION(3,0,0) 323 | gtk_table_attach (GTK_TABLE (table), l, i, i + 1, 1, 2, GTK_FILL, 0, 2, 2); 324 | #else 325 | gtk_grid_attach (GTK_GRID (table), l, i, 1, 1, 1); 326 | #endif 327 | else 328 | #if !GTK_CHECK_VERSION(3,0,0) 329 | gtk_table_attach (GTK_TABLE (table), l, 0, 1, i, i + 1, GTK_FILL, 0, 2, 2); 330 | #else 331 | gtk_grid_attach (GTK_GRID (table), l, 0, i, 1, 1); 332 | #endif 333 | 334 | /* add progress bar */ 335 | w = gtk_progress_bar_new (); 336 | gtk_widget_set_name (w, "yad-progress-widget"); 337 | #if GTK_CHECK_VERSION(3,0,0) 338 | gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR (w), !options.common_data.hide_text); 339 | #endif 340 | 341 | #if !GTK_CHECK_VERSION(3,0,0) 342 | /* The maintain-gtk2 branch keeps forward compatibility with master for GTK 3 builds only */ 343 | /* Here maintain-gtk2 keeps backward compatibility */ 344 | if (single_mode) 345 | { 346 | if (options.progress_data.percentage > 100) 347 | options.progress_data.percentage = 100; 348 | gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w), options.progress_data.percentage / 100.0); 349 | 350 | /* writes updatable text inside the bar */ 351 | if (options.progress_data.progress_text && !options.common_data.hide_text) 352 | gtk_progress_bar_set_text (GTK_PROGRESS_BAR (w), options.progress_data.progress_text); 353 | } 354 | #endif 355 | 356 | if (p->type != YAD_PROGRESS_PULSE) 357 | { 358 | if (options.extra_data && options.extra_data[i]) 359 | { 360 | if (g_ascii_isdigit (*options.extra_data[i])) 361 | gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (w), atoi (options.extra_data[i]) / 100.0); 362 | } 363 | } 364 | else 365 | { 366 | if (options.extra_data && options.extra_data[i]) 367 | { 368 | if (g_ascii_isdigit (*options.extra_data[i])) 369 | gtk_progress_bar_set_pulse_step (GTK_PROGRESS_BAR (w), atoi (options.extra_data[i]) / 100.0); 370 | } 371 | } 372 | 373 | #if GTK_CHECK_VERSION(3,0,0) 374 | gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR (w), p->type == YAD_PROGRESS_RTL); 375 | if (options.common_data.vertical) 376 | gtk_orientable_set_orientation (GTK_ORIENTABLE (w), GTK_ORIENTATION_VERTICAL); 377 | #else 378 | if (p->type == YAD_PROGRESS_RTL) 379 | { 380 | if (options.common_data.vertical) 381 | gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (w), GTK_PROGRESS_TOP_TO_BOTTOM); 382 | else 383 | gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (w), GTK_PROGRESS_RIGHT_TO_LEFT); 384 | } 385 | else 386 | { 387 | if (options.common_data.vertical) 388 | gtk_progress_bar_set_orientation (GTK_PROGRESS_BAR (w), GTK_PROGRESS_BOTTOM_TO_TOP); 389 | } 390 | #endif 391 | if (options.common_data.vertical) 392 | { 393 | #if !GTK_CHECK_VERSION(3,0,0) 394 | gtk_table_attach (GTK_TABLE (table), w, i, i + 1, 0, 1, 0, GTK_FILL | GTK_EXPAND, 2, 2); 395 | #else 396 | gtk_grid_attach (GTK_GRID (table), w, i, 0, 1, 1); 397 | gtk_widget_set_vexpand (w, TRUE); 398 | #endif 399 | } 400 | else 401 | { 402 | #if !GTK_CHECK_VERSION(3,0,0) 403 | gtk_table_attach (GTK_TABLE (table), w, 1, 2, i, i + 1, GTK_FILL | GTK_EXPAND, 0, 2, 2); 404 | #else 405 | gtk_grid_attach (GTK_GRID (table), w, 1, i, 1, 1); 406 | gtk_widget_set_hexpand (w, TRUE); 407 | #endif 408 | } 409 | 410 | progress_bars = g_slist_append (progress_bars, w); 411 | 412 | i++; 413 | } 414 | 415 | if (options.progress_data.log) 416 | { 417 | GtkWidget *ex, *sw; 418 | 419 | ex = gtk_expander_new (options.progress_data.log); 420 | gtk_expander_set_spacing (GTK_EXPANDER (ex), 2); 421 | gtk_expander_set_expanded (GTK_EXPANDER (ex), options.progress_data.log_expanded); 422 | 423 | #if !GTK_CHECK_VERSION(3,0,0) 424 | if (options.common_data.vertical) 425 | gtk_table_attach (GTK_TABLE (table), ex, 0, i + 1, 1, 2, GTK_FILL, 0, 2, 2); 426 | else 427 | gtk_table_attach (GTK_TABLE (table), ex, 0, 2, i, i + 1, GTK_FILL, 0, 2, 2); 428 | #else 429 | if (options.common_data.vertical) 430 | gtk_grid_attach (GTK_GRID (table), ex, 0, 2, i, 1); 431 | else 432 | gtk_grid_attach (GTK_GRID (table), ex, 0, i, 2, 1); 433 | #endif 434 | 435 | sw = gtk_scrolled_window_new (NULL, NULL); 436 | gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_ETCHED_IN); 437 | gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), options.data.hscroll_policy, options.data.vscroll_policy); 438 | #if GTK_CHECK_VERSION(3,22,0) 439 | gtk_scrolled_window_set_propagate_natural_height (GTK_SCROLLED_WINDOW (sw), TRUE); 440 | #endif 441 | gtk_container_add (GTK_CONTAINER (ex), sw); 442 | 443 | progress_log = gtk_text_view_new (); 444 | gtk_widget_set_name (progress_log, "yad-text-widget"); 445 | gtk_widget_set_size_request (progress_log, -1, options.progress_data.log_height); 446 | gtk_container_add (GTK_CONTAINER (sw), progress_log); 447 | 448 | log_buffer = gtk_text_buffer_new (NULL); 449 | gtk_text_view_set_buffer (GTK_TEXT_VIEW (progress_log), log_buffer); 450 | gtk_text_view_set_left_margin (GTK_TEXT_VIEW (progress_log), 5); 451 | gtk_text_view_set_right_margin (GTK_TEXT_VIEW (progress_log), 5); 452 | gtk_text_view_set_editable (GTK_TEXT_VIEW (progress_log), FALSE); 453 | gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (progress_log), FALSE); 454 | } 455 | 456 | channel = g_io_channel_unix_new (0); 457 | g_io_channel_set_encoding (channel, NULL, NULL); 458 | g_io_channel_set_flags (channel, G_IO_FLAG_NONBLOCK, NULL); 459 | g_io_add_watch (channel, G_IO_IN | G_IO_HUP, handle_stdin, dlg); 460 | 461 | return w; 462 | } 463 | --------------------------------------------------------------------------------