Skip to content

Commit 668d666

Browse files
committed
✨ feat: feat: integrate Application Mode, fix custom icons, improve icon selector
Application Mode ("Modo Aplicativo") integration: - webapp_model.py: add app_mode field ("browser"|"app"), default "browser" - webapp_dialog.py: add Application Mode toggle (Adw.ActionRow + Gtk.Switch), hide browser/profile rows when active, restore on deactivate - command_executor.py: pass "__viewer__" as browser when app_mode == "app" - big-webapps (bash): create viewer .desktop with big-webapps-viewer Exec line, add StartupWMClass=br.com.biglinux.webapp.$app_id for taskbar icon matching, json command detects both big-webapps-exec and big-webapps-viewer files, Exec parser extracts --url from viewer lines, short_browser maps __viewer__ to "viewer" for filename generation, app_mode included in JSON output Fix custom icon persistence: - big-webapps: copy custom icons to ~/.local/share/icons/hicolor/scalable/apps/ (proper icon theme hierarchy) instead of flat ~/.local/share/icons/, use absolute path in Icon= field so desktop environment resolves correctly - big-webapps: remove broken icon normalization in JSON parsing that was overwriting .desktop files and stripping paths unnecessarily - webapp_model.py: app_icon_url falls back to app_icon when empty, fixing icon loss when editing webapp without changing icon Icon selector improvements (select_icon.sh): - Persist last-used directory in ~/.config/biglinux-webapps/last_icon_dir, zenity/yad opens in last chosen folder on subsequent selections - Fix geticons resolution: "; exit" was unconditionally exiting after first size attempt — replaced with proper loop over sizes 128→64→48→32 - Add stderr redirect (2>&1) to "type" checks for cleaner output UI cleanup: - main_window.py: remove app icon from header bar (left side) - command_executor.py: add debug logging for create_webapp argv and icon values
1 parent 8dd2e5a commit 668d666

File tree

7 files changed

+140
-55
lines changed

7 files changed

+140
-55
lines changed

biglinux-webapps/usr/bin/big-webapps

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -110,22 +110,27 @@ else
110110
name="$2"
111111
url="$3"
112112
icon="$4"
113-
# If icon not in the icon folder, copy to the icon folder
113+
# If icon has a path, copy to proper icon theme dir and use absolute path
114114
if [[ $icon =~ \/ ]]; then
115-
cp "$icon" ~/.local/share/icons/
115+
mkdir -p ~/.local/share/icons/hicolor/scalable/apps
116+
icon_basename="${icon##*/}"
117+
cp "$icon" ~/.local/share/icons/hicolor/scalable/apps/
118+
icon="$HOME/.local/share/icons/hicolor/scalable/apps/$icon_basename"
116119
fi
117-
icon=${icon//*\/}
118-
icon=${icon%.*}
119120
category="$5"
120121
profile="$6"
121122
fi
122123

123124

124125
# Adjust the browser name for the filename and class
125-
short_browser=$(sed 's/.*[Cc]hrom.*/chrome/
126-
s/.*[Bb]rave.*/brave/
127-
s/.*[Ee]dge.*/msedge/
128-
s/.*[Vv]ivaldi.*/vivaldi/' <<< "$browser")
126+
if [[ "$browser" == "__viewer__" ]]; then
127+
short_browser="viewer"
128+
else
129+
short_browser=$(sed 's/.*[Cc]hrom.*/chrome/
130+
s/.*[Bb]rave.*/brave/
131+
s/.*[Ee]dge.*/msedge/
132+
s/.*[Vv]ivaldi.*/vivaldi/' <<< "$browser")
133+
fi
129134

130135
# Adjust the class by replacing "/" with "__" and removing https
131136
class=$(sed 's|https://||;s|http://||g;s|/|__|g' <<< "$url")
@@ -160,20 +165,38 @@ if [ "$command" = "create" ]; then
160165
exit 1
161166
fi
162167

163-
# Create the .desktop file
164-
read -d $'' ShowText <<EOF
168+
if [[ "$browser" == "__viewer__" ]]; then
169+
# App mode — Qt6 viewer without browser chrome
170+
app_id=$(sed 's|https://||;s|http://||;s|/|_|g;s|[^a-zA-Z0-9_-]||g' <<< "$url")
171+
read -d $'' ShowText <<EOF
172+
#!/usr/bin/env xdg-open
173+
[Desktop Entry]
174+
Version=1.0
175+
Terminal=false
176+
Type=Application
177+
Name=$name
178+
Exec=big-webapps-viewer --url="$url" --name="$name" --icon="${icon}" --app-id="$app_id"
179+
Icon=$icon
180+
StartupWMClass=br.com.biglinux.webapp.$app_id
181+
Categories=$category
182+
StartupNotify=false
183+
EOF
184+
else
185+
# Browser mode — standard webapp
186+
read -d $'' ShowText <<EOF
165187
#!/usr/bin/env xdg-open
166188
[Desktop Entry]
167189
Version=1.0
168190
Terminal=false
169191
Type=Application
170192
Name=$name
171193
Exec=big-webapps-exec filename="$filename" $browser --class="$class" --profile-directory=$profile --app="$url"
172-
Icon=${icon//*\/}
194+
Icon=$icon
173195
StartupWMClass=$class
174196
Categories=$category
175197
StartupNotify=false
176198
EOF
199+
fi
177200

178201
echo "$ShowText" > "$filename"
179202

@@ -205,7 +228,7 @@ elif [ "$command" = "json" ]; then
205228
IFS=$'\n'
206229
# Get if not passed the files, show all files with big-webapps-exec
207230
if [[ -z $one_file ]]; then
208-
files=$(grep -Rl 'big-webapps-exec')
231+
files=$(grep -Rl 'big-webapps-exec\|big-webapps-viewer')
209232
else
210233
files=$one_file
211234
fi
@@ -223,23 +246,25 @@ elif [ "$command" = "json" ]; then
223246
name=${line#*Name=}
224247
;;
225248
"Exec="*)
226-
url=${line//*--app=}
227-
url=${url//\"}
228-
browser=${line//*filename=\"}
229-
browser=${browser#*\" }
230-
browser=${browser// *}
231-
profile=${line//*--profile-directory=}
232-
profile=${profile// *}
249+
if [[ "$line" == *"big-webapps-viewer"* ]]; then
250+
# App mode — Qt6 viewer
251+
url=${line//*--url=\"}
252+
url=${url//\"*}
253+
browser="__viewer__"
254+
profile="Default"
255+
else
256+
# Browser mode
257+
url=${line//*--app=}
258+
url=${url//\"}
259+
browser=${line//*filename=\"}
260+
browser=${browser#*\" }
261+
browser=${browser// *}
262+
profile=${line//*--profile-directory=}
263+
profile=${profile// *}
264+
fi
233265
;;
234266
"Icon="*)
235267
icon=${line#*Icon=}
236-
# Copy the icon to the applications folder if it's not a system icon
237-
if [[ $icon =~ \/ ]]; then
238-
cp "$icon" ~/.local/share/icons/
239-
sed -Ei 's|^Icon=.*/(.*)\..*|Icon=\1|g' "$file"
240-
fi
241-
icon=${icon//*\/}
242-
# icon=${icon%.*}
243268
;;
244269
"Categories="*)
245270
categories=${line#*Categories=}
@@ -252,6 +277,13 @@ elif [ "$command" = "json" ]; then
252277
echo ,
253278
fi
254279

280+
# Determine app_mode from browser
281+
if [[ "$browser" == "__viewer__" ]]; then
282+
app_mode="app"
283+
else
284+
app_mode="browser"
285+
fi
286+
255287
# Print the JSON object with escaped quotes
256288
read -d $'' ShowText <<EOF
257289
{
@@ -261,7 +293,8 @@ elif [ "$command" = "json" ]; then
261293
"app_url": "${url//\"/\\\\\"}",
262294
"app_icon": "$icon",
263295
"app_profile": "$profile",
264-
"app_categories": "$categories"
296+
"app_categories": "$categories",
297+
"app_mode": "$app_mode"
265298
}
266299
EOF
267300
echo "$ShowText"

biglinux-webapps/usr/bin/big-webapps-viewer

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
CSD headerbar replicating GTK4/Adwaita style. Fullscreen auto-hide overlay.
44
"""
55

6-
APP_VERSION = "3.2.0"
6+
APP_VERSION = "3.3.0"
77

88
import argparse
99
import json

biglinux-webapps/usr/share/biglinux/webapps/select_icon.sh

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,38 @@
22

33
# The output of this script is the path of the icon selected by the user
44

5+
# Persist last-used directory
6+
LAST_DIR_FILE="$HOME/.config/biglinux-webapps/last_icon_dir"
7+
last_dir=""
8+
if [[ -f "$LAST_DIR_FILE" ]]; then
9+
last_dir=$(<"$LAST_DIR_FILE")
10+
fi
11+
512
# Use type to check if a command exists
6-
if type kdialog >/dev/null; then
13+
if type kdialog >/dev/null 2>&1; then
714
icon=$(kdialog --geticon Applications 2> /dev/null)
8-
elif type zenity >/dev/null; then
9-
icon=$(zenity --file-selection --file-filter="image|*.[Jj][Pp][Gg] *.[Jj][Pp][Ee][Gg] *.[Pp][Nn][Gg] *.[Ss][Vv][Gg] *.[Ss][Vv][Gg][Zz] *.[Ww][Ee][Bb][Pp]")
10-
elif type yad >/dev/null; then
11-
icon=$(cd ~; yad --file --add-preview --large-preview --file-filter="image|*.[Jj][Pp][Gg] *.[Jj][Pp][Ee][Gg] *.[Pp][Nn][Gg] *.[Ss][Vv][Gg] *.[Ss][Vv][Gg][Zz] *.[Ww][Ee][Bb][Pp]")
15+
elif type zenity >/dev/null 2>&1; then
16+
icon=$(zenity --file-selection ${last_dir:+--filename="$last_dir/"} --file-filter="image|*.[Jj][Pp][Gg] *.[Jj][Pp][Ee][Gg] *.[Pp][Nn][Gg] *.[Ss][Vv][Gg] *.[Ss][Vv][Gg][Zz] *.[Ww][Ee][Bb][Pp]")
17+
elif type yad >/dev/null 2>&1; then
18+
icon=$(cd "${last_dir:-$HOME}"; yad --file --add-preview --large-preview --file-filter="image|*.[Jj][Pp][Gg] *.[Jj][Pp][Ee][Gg] *.[Pp][Nn][Gg] *.[Ss][Vv][Gg] *.[Ss][Vv][Gg][Zz] *.[Ww][Ee][Bb][Pp]")
19+
fi
20+
21+
# Save chosen directory for next time
22+
if [[ $icon =~ / ]]; then
23+
mkdir -p "$(dirname "$LAST_DIR_FILE")"
24+
dirname "$icon" > "$LAST_DIR_FILE"
1225
fi
1326

1427
# If icon don't have a path, get the icon with path
1528
if [[ $icon =~ / ]]; then
1629
echo "$icon"
17-
else
18-
icon_address=$(geticons -s 128 "$icon")
19-
[ -n "$icon_address" ] && echo "$icon_address"; exit
20-
icon_address=$(geticons -s 64 "$icon")
21-
[ -n "$icon_address" ] && echo "$icon_address"; exit
22-
icon_address=$(geticons -s 48 "$icon")
23-
[ -n "$icon_address" ] && echo "$icon_address"; exit
24-
icon_address=$(geticons -s 32 "$icon")
25-
[ -n "$icon_address" ] && echo "$icon_address"; exit
26-
geticons "$icon"
30+
elif [[ -n "$icon" ]]; then
31+
for sz in 128 64 48 32; do
32+
icon_address=$(geticons -s "$sz" "$icon" 2>/dev/null)
33+
if [[ -n "$icon_address" ]]; then
34+
echo "$icon_address"
35+
exit
36+
fi
37+
done
38+
geticons "$icon" 2>/dev/null
2739
fi

biglinux-webapps/usr/share/biglinux/webapps/webapps/models/webapp_model.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def __init__(self, app_data: dict | None = None) -> None:
2929
self.app_profile = "Default"
3030
self.app_categories = "Webapps"
3131
self.app_icon_url = ""
32+
self.app_mode = "browser" # "browser" or "app"
3233

3334
# Load data if provided
3435
if app_data:
@@ -43,7 +44,8 @@ def load_from_dict(self, app_data: dict) -> None:
4344
self.app_icon = app_data.get("app_icon", "")
4445
self.app_profile = app_data.get("app_profile", "Default")
4546
self.app_categories = app_data.get("app_categories", "Webapps")
46-
self.app_icon_url = app_data.get("app_icon_url", "")
47+
self.app_icon_url = app_data.get("app_icon_url", "") or self.app_icon
48+
self.app_mode = app_data.get("app_mode", "browser")
4749

4850
def get_main_category(self) -> str:
4951
"""

biglinux-webapps/usr/share/biglinux/webapps/webapps/ui/main_window.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,6 @@ def setup_ui(self) -> None:
6161
# Header bar
6262
header = Adw.HeaderBar()
6363

64-
# App icon on the left
65-
app_icon = Gtk.Image.new_from_icon_name("big-webapps")
66-
app_icon.set_pixel_size(24)
67-
header.pack_start(app_icon)
68-
6964
# Search button on the left
7065
search_button = Gtk.ToggleButton(icon_name="system-search-symbolic")
7166
search_button.connect("toggled", self.on_search_toggled)

biglinux-webapps/usr/share/biglinux/webapps/webapps/ui/webapp_dialog.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ def _clone_webapp(self, webapp: WebApp) -> WebApp:
144144
"app_profile": webapp.app_profile,
145145
"app_categories": webapp.app_categories,
146146
"app_icon_url": webapp.app_icon_url,
147+
"app_mode": webapp.app_mode,
147148
}
148149

149150
return WebApp(webapp_dict)
@@ -285,8 +286,20 @@ def setup_ui(self) -> None:
285286
category_row.add_suffix(self.category_dropdown)
286287
form_group.add(category_row)
287288

289+
# App mode toggle — opens in Qt6 viewer instead of browser
290+
self.app_mode_row = Adw.ActionRow(title=_("Application Mode"))
291+
self.app_mode_row.set_subtitle(
292+
_("Opens as a native window without browser interface")
293+
)
294+
self.app_mode_switch = Gtk.Switch()
295+
self.app_mode_switch.set_valign(Gtk.Align.CENTER)
296+
self.app_mode_switch.set_active(self.webapp.app_mode == "app")
297+
self.app_mode_switch.connect("notify::active", self.on_app_mode_switch_changed)
298+
self.app_mode_row.add_suffix(self.app_mode_switch)
299+
form_group.add(self.app_mode_row)
300+
288301
# Browser selection
289-
browser_row = Adw.ActionRow(title=_("Browser"))
302+
self.browser_row = Adw.ActionRow(title=_("Browser"))
290303

291304
browser_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
292305
self.browser_icon = Gtk.Image()
@@ -298,13 +311,13 @@ def setup_ui(self) -> None:
298311
self.set_browser_label(self.webapp.browser)
299312
browser_box.append(self.browser_label)
300313

301-
browser_row.add_prefix(browser_box)
314+
self.browser_row.add_prefix(browser_box)
302315

303316
select_browser_button = Gtk.Button(label=_("Select"))
304317
select_browser_button.connect("clicked", self.on_select_browser_clicked)
305318
select_browser_button.set_valign(Gtk.Align.CENTER)
306-
browser_row.add_suffix(select_browser_button)
307-
form_group.add(browser_row)
319+
self.browser_row.add_suffix(select_browser_button)
320+
form_group.add(self.browser_row)
308321

309322
# Profile settings
310323
browser = self.browser_collection.get_by_id(self.webapp.browser)
@@ -341,6 +354,12 @@ def setup_ui(self) -> None:
341354
form_group.add(self.profile_row)
342355
form_group.add(self.profile_entry_row)
343356

357+
# Hide browser/profile rows when app mode is active
358+
if self.webapp.app_mode == "app":
359+
self.browser_row.set_visible(False)
360+
self.profile_row.set_visible(False)
361+
self.profile_entry_row.set_visible(False)
362+
344363
# Add form group to the layout
345364
form_box.append(form_group)
346365

@@ -524,6 +543,18 @@ def on_category_changed(
524543
self.webapp.set_main_category(display_category)
525544
logger.warning("Fallback: using display category: %s", display_category)
526545

546+
def on_app_mode_switch_changed(
547+
self, switch: Gtk.Switch, _param: GObject.ParamSpec
548+
) -> None:
549+
"""Toggle between browser mode and application mode."""
550+
is_app = switch.get_active()
551+
self.webapp.app_mode = "app" if is_app else "browser"
552+
self.browser_row.set_visible(not is_app)
553+
self.profile_row.set_visible(not is_app)
554+
self.profile_entry_row.set_visible(
555+
not is_app and self.profile_switch.get_active()
556+
)
557+
527558
def on_profile_switch_changed(
528559
self, switch: Gtk.Switch, _param: GObject.ParamSpec
529560
) -> None:

biglinux-webapps/usr/share/biglinux/webapps/webapps/utils/command_executor.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,26 @@ def create_webapp(self, webapp) -> bool:
115115
Returns:
116116
True if successful
117117
"""
118+
browser = "__viewer__" if webapp.app_mode == "app" else webapp.browser
118119
argv = [
119120
"big-webapps",
120121
"create",
121-
webapp.browser,
122+
browser,
122123
webapp.app_name,
123124
webapp.app_url,
124125
webapp.app_icon_url,
125126
webapp.app_categories,
126127
webapp.app_profile,
127128
]
129+
logger.debug("create_webapp argv: %s", argv)
130+
logger.debug(
131+
"create_webapp icon_url=%r icon=%r", webapp.app_icon_url, webapp.app_icon
132+
)
133+
print(
134+
f"[DEBUG] create_webapp icon_url={webapp.app_icon_url!r} icon={webapp.app_icon!r}",
135+
flush=True,
136+
)
137+
print(f"[DEBUG] create_webapp argv={argv}", flush=True)
128138
output = self.execute_command(argv)
129139
return output != ""
130140

@@ -178,7 +188,9 @@ def select_icon(self) -> str:
178188
Returns:
179189
Path to the selected icon
180190
"""
181-
return self.execute_command(["./select_icon.sh"]).strip()
191+
result = self.execute_command(["./select_icon.sh"]).strip()
192+
print(f"[DEBUG] select_icon result={result!r}", flush=True)
193+
return result
182194

183195
def get_system_default_browser(self) -> str | None:
184196
"""

0 commit comments

Comments
 (0)