Compare commits

...

127 Commits

Author SHA1 Message Date
Sanel Z
9804f0e93a
Merge pull request #1 from kraileth/readme-improvement
Improve readme
2018-05-22 14:22:14 +02:00
Sanel Zukan
a04496c7f0 Do not handle manual for now. 2018-05-22 14:01:57 +02:00
Michael Reim
84f195c9b7 Improve readme 2018-05-04 20:28:07 +02:00
Sanel Zukan
5489ef0b70 Prevent crash when focusing button. 2018-05-04 00:52:05 +02:00
Sanel Zukan
cbcb0e2ce4 Show status when battery query fails.
When there is an issue with getting battery details, panel would not
show any icon nor tooltip to mark that status. This changes adds failing
icon and appropriate tooltip message.
2016-07-13 16:07:02 +02:00
Sanel Zukan
09039b46c9 Changed default gtk+ theme.
For now, relay on Adwaita gtk+3 theme. For future, a better approach
should be considered.
2016-07-13 12:53:12 +02:00
Sanel Zukan
7cc34bd248 Make sure 'lib' folders are created first. 2016-07-13 12:52:36 +02:00
Sanel Zukan
482ced1c5c Use rsvg-convert as svg convertor. 2016-06-29 13:27:02 +02:00
Sanel Zukan
f09dd4d3d6 Fixing links. 2016-06-16 14:51:33 +02:00
Sanel Zukan
9c6d7ebd0e Updating. 2016-06-16 14:49:39 +02:00
Sanel Zukan
9029fb2f45 Renaming. 2016-06-16 14:45:08 +02:00
Sanel Zukan
6f0fa02cbe Reordering repository 2016-06-08 12:33:37 +00:00
Sanel Zukan
f799482f64 DBus in most cases requres pthreads library, especially on OpenBSD in this case. 2015-12-17 00:13:09 +00:00
Sanel Zukan
da0370a255 Allow ede-startup.conf values to be overwritten by user specific startup sequence. 2015-12-17 00:05:32 +00:00
Sanel Zukan
3042413e36 Applying patches from Michael to fix openbsd buils. Fixing notification daemon to properly read 'replaces' property. 2015-12-16 17:05:02 +00:00
Sanel Zukan
29475da925 Allow setting splash theme to 'none'.
If 'none' was set, no splash theme will be used. This is another way
splash screen can be disabled without adding '-n' option to evoke.
2014-12-08 23:00:55 +00:00
Sanel Zukan
09b1d6fe74 Sort entries before they are added to the menu list. 2014-12-04 17:08:01 +00:00
Sanel Zukan
ef64e70a8b Sort layout descriptions. 2014-12-03 20:48:44 +00:00
Sanel Zukan
bd1f834431 Removed comments that prevented applet loading 2014-11-29 02:49:04 +00:00
Sanel Zukan
8f5f3a94ca Cleanup. 2014-11-29 02:43:19 +00:00
Sanel Zukan
e154972cdd Small code cleanup. Use the same code for tiling as ede-desktop is using it; this will make tile preview to look the same as will be on desktop background. 2014-11-28 17:45:41 +00:00
Sanel Zukan
8f8a937e98 Added support for wallpaper size update when screen sizes are changed. Also, there are some tricks applied so wallpaper scaling be done only when really is needed. 2014-11-28 15:46:05 +00:00
Sanel Zukan
f0c50eeebf Fixing issue with workspace change and window listing. Adding facility for reading configuration from applets: implemting options for configuring fixed layout in taskbar tabs and showing buttons from all desktops. 2014-11-28 01:47:31 +00:00
Sanel Zukan
002bd6b2e7 Adding support for taskbuttons drag & drop. Also fixing child size check bug. 2014-11-19 12:40:42 +00:00
Sanel Zukan
0d0cc8d8b1 Fixing bug 208 - Panel (position 0!) displaced on startup 2014-07-09 12:50:17 +00:00
Sanel Zukan
a2b2ae0e27 Adding patch from kraileth, which makes tip compiler compileable with musl libc. 2014-07-09 11:07:06 +00:00
Sanel Zukan
e529fb9794 Increasing version number. 2014-06-23 21:11:41 +00:00
Sanel Zukan
cdccbe7ce6 Updating (c) year in about dialog. 2014-06-21 20:55:47 +00:00
Sanel Zukan
a735fa7e84 Added logout dialog, confirmation is now binded to Enter key. 2014-06-20 09:29:18 +00:00
Sanel Zukan
7ebc86ca41 Fixing report string. 2014-06-20 09:27:40 +00:00
Sanel Zukan
d6dd94778c Cleaning some compiler warnings. 2014-03-02 11:12:17 +00:00
Sanel Zukan
f1a37cefd2 Changed icon create/edit dialog, so working path can be set, including startup options like running in terminal or starting with startup nofication hints.
Changed how icons are started. Previously, ede-desktop would extract content from .desktop Exec key and explicitly run it. This would not correctly handle other .desktop details, like startup notification or running in terminal. Now, full .desktop path is sent directly to ede-launch which will take care about named startup details.

These changes also fixes bug #235: "Working directory and startup notification for desktop icons".
2014-02-25 18:16:10 +00:00
Sanel Zukan
30d0261cd3 If .desktop file set Path key, obey to it and change current working directory. 2014-02-25 18:02:39 +00:00
Sanel Zukan
97886f254a free() requires stdlib.h, which is visible in FLTK 1.3 2013-10-28 23:47:11 +00:00
Sanel Zukan
095feb98e7 Allow last changes to be compileable with FLTK 1.1.x. This way I found some rand()/srand() calls without stdlib.h inclusion... 2013-10-28 23:42:40 +00:00
Sanel Zukan
361d3a532a Show tooltip over icon if icon contains Comment key. 2013-10-28 21:51:05 +00:00
Sanel Zukan
2c9f804aa3 Removing emountd; this code isn't used much as HAL is deprecated long time ago. Obviously, mounting notifications will be redone in future. 2013-10-02 01:35:18 +00:00
Sanel Zukan
bee5fd8fb9 Removing old ede-desktop.h. Adding support for editing existing icons.
Editing will be done simply by creating first .desktop file and letting ede-desktop to read it, performing some
checks to determin if only content was changed or file was renamed. Using this scheme, beside it simplify the code,
it addresses the cases when icon was modified outside the desktop or removed.

These things could be solved by using DirWatch, but I'm trying to rely less on OS notification system...
2013-06-24 14:40:28 +00:00
Sanel Zukan
db9e0bad61 Added fallback in case dirent's d_type wasn't set. Seems how Slackware follows POSIX strictly than others. 2013-06-07 22:19:00 +00:00
Sanel Zukan
fc433aa342 Better handling if configuration isn't present. 2013-06-06 09:48:01 +00:00
Sanel Zukan
0d6f18e867 Do not exit from read_config() even if reading file fails; edelib::Config class will simply use fallback values instead. 2013-06-06 09:44:50 +00:00
Sanel Zukan
932e2c85fd Load hider too. 2013-06-06 09:04:42 +00:00
Sanel Zukan
2726a2af37 Do not return from read_config() when configuration isn't present: applet will not be loaded. 2013-06-06 09:00:44 +00:00
Sanel Zukan
756b95587d Fixing some accidentaly lowered chars. 2013-06-05 16:34:06 +00:00
Sanel Zukan
6d1a140375 Changing uneeded const specifier for given va_list type. 2013-06-04 09:59:35 +00:00
Sanel Zukan
ca5911fe94 Use flat box so redraw() can update changed image correctly. 2013-06-03 21:47:26 +00:00
Sanel Zukan
05f7fc15e1 Inside battery applet, do not load icon on every change event by device. Instead, check if we really need to change icon (e.g. states between 'battery' and 'battery-caution' are changed) then load it.
A small formatting inside Panle and AppletManager.
2013-06-03 17:39:50 +00:00
Sanel Zukan
b24b859a4f Read applets and hider from configuration. Go to builtin order as fallback. 2013-06-03 13:44:59 +00:00
Sanel Zukan
8a0f7135ee Load system wide battery applet installation. Also added explicit linkage for libdl... 2013-06-03 11:15:59 +00:00
Sanel Zukan
a2a6f6034d Removed some test code. 2013-06-03 11:11:57 +00:00
Sanel Zukan
d30685514c In case DBus wasn't available, do not compile DBus related code. 2013-06-03 11:11:07 +00:00
Sanel Zukan
85490945e6 Importing UPower powered battery monitor. 2013-06-03 11:01:38 +00:00
Sanel Zukan
5bfe346880 Manualy merging ede-desktop2 branch. SF merging facility (ignores valid login) sux badly. 2013-05-30 13:07:49 +00:00
Sanel Zukan
9d1f4699de These days linking with XShape extension must be done explicitly. 2013-05-30 12:31:25 +00:00
Sanel Zukan
70e9a9b0b6 Cleaned a little bit strut handling. Oddly, this fixed strut ignoring value for xfwm4... 2013-03-04 23:18:17 +00:00
Sanel Zukan
a8b01d75c1 Set XDG_CURRENT_DESKTOP on startup. 2013-02-18 23:38:52 +00:00
Sanel Zukan
c8323b386d Do not run .desktop files which has OnlyShowIn/NotShowIn without 'EDE' as key. 2013-02-04 00:02:28 +00:00
Sanel Zukan
229914358a Support for panel height resize.
Now, when panel height get resized, children will update their height's too. Children height is always calculated in form (parent()->h() - 10).
2013-01-17 23:53:11 +00:00
Sanel Zukan
7c4628dfa1 Prevent switch to different workspace when minimizing last window on current workspace. 2013-01-17 22:49:49 +00:00
Sanel Zukan
7760130feb Updating year... 2013-01-16 22:47:33 +00:00
Sanel Zukan
8237708d54 Fixed disabled #ifdef. Also moved refresh interval on 2secs, to easy panel a little bit. 2013-01-11 19:03:37 +00:00
Sanel Zukan
19da305d71 Warning cleanup. 2013-01-09 16:06:45 +00:00
Sanel Zukan
0b4d9a7f26 More work on opensolaris...
Cleaning some warnings.
Added checks for kstat, so cpu applet can show usage via kstat api. Added tests for kstat in configure script.
2013-01-09 16:01:35 +00:00
Sanel Zukan
6495f53404 In case we do not have sysinfo() (!linux), create plain box with some info about it. 2013-01-09 14:04:51 +00:00
Sanel Zukan
d0d94e21dd Comment local applets option. 2013-01-09 13:47:08 +00:00
Sanel Zukan
465eb7dfe3 Moving memory query status code to use sysinfo() instead of /proc. 2013-01-09 13:45:49 +00:00
Sanel Zukan
e01506d58a Fixed stupid opensolaris requirement for c98... 2013-01-09 13:15:03 +00:00
Sanel Zukan
e4cf7ba8cf Use more space for key values. 2013-01-07 15:11:54 +00:00
Sanel Zukan
24a85295fa Added a few terms more. 2013-01-07 15:09:40 +00:00
Sanel Zukan
b5d2e20cee Fix for #186: ede-launch does not read Terminal key from desktop.
ede-launch now will read Terminal key, and if set to true, will load default selected terminal (or one of known terminals). It will also read now StartupNotify key, and initiate startup-notification protocol if compiled in; by default, it will not use startup notifications.

Resource loading is now made lazy, so first need for ede-launch configuration will load it from file.
2013-01-07 15:07:24 +00:00
Sanel Zukan
31d35e627a Fixed #194: ede-desktop will not save icon position on Shutdown. Code cleanup.
When user hit shutdown or restart from dialog, evoke will immediately sent shutdown/restart signal, causing abnormal X termination, killing all childs. With this commit, evoke will first close all X childs, then send shutdown/restart signal.
2013-01-05 03:39:09 +00:00
Sanel Zukan
c93bfdf7ee Fix for icon pick from icon chooser.
Now loader will use IconLoader::set() to fetch icon from choosen result.
2013-01-04 15:01:55 +00:00
Sanel Zukan
6a7296bcae Comment debug build. 2013-01-04 14:38:33 +00:00
Sanel Zukan
7b1245f06a Moving hider to panel itself, instead as separate applet.
Hider calls some Panel specific code and doing that from applet will make shit like selinux or apparmor quite unhappy (due relocations), which will refuse to start ede-panel. ...yet another workaround for that crapy security junk.
2013-01-04 14:36:40 +00:00
Sanel Zukan
d09f846380 Better handling on workspace change and setting sticky tag for window. Implemented #217: all windows in taskbar, no matter which desktop was used. 2013-01-04 13:05:42 +00:00
Sanel Zukan
7431373b29 Speed up removal items from group (FLTK 1.3 added faster method). Also fixing strange issue with desktop switch during minimize.
Added AppletWidget class, an experimental code for widgets that wants to accept custom methods. Needs completion though
2013-01-04 10:33:53 +00:00
Sanel Zukan
22f4e094cf Do not create unnecessary test binary. This also prevents TEXTRELS errors on systems where relocations are tracked. 2012-12-27 15:34:59 +00:00
Sanel Zukan
1046c2d4d5 Used new features from IconChooser. 2012-12-26 01:53:08 +00:00
Sanel Zukan
97da788155 Fixing #211: startede refers to old X11R6 resource path.
In startede sysresources are refering to older X11R6 (now is X11R7). Also as reported, on some systems the path '/usr/X11' is used too. Solving by removing resource usage at all; not seeing any usefulness of it...
2012-12-20 12:32:44 +00:00
Sanel Zukan
3df8f4ed7e Fixing long standing issue with tray space when tray icon gets destroyed.
When tray icon gets destroyed, space it was occupying would not be cleaned, yielding wholes inside taskbar. Fixing by explicitly hiding and deleting FLTK window which holded application tray window.
2012-12-20 01:50:00 +00:00
Sanel Zukan
eed00b3fbc Added title for panel and desktop, so we can find them in xrestop list. 2012-12-20 01:16:01 +00:00
Sanel Zukan
8bb9028df3 Implementing #213 (Make taskbar buttons stretchable).
Taskbar buttons now can be stretchable or fixed size as before. This commit also fixes a couple of drawing issues when workspace was changed.
2012-12-20 00:58:30 +00:00
Sanel Zukan
a3f2a79d5f Looks like sawfish likes WM_WINDOW_STATE_ICONIC more than NETWM_STATE_HIDDEN. 2012-12-17 22:26:55 +00:00
Sanel Zukan
fc4474f1c7 Removed usage... 2012-12-17 18:58:39 +00:00
Sanel Zukan
68959abca2 Removed unused list. 2012-12-17 18:56:59 +00:00
Sanel Zukan
fb708f76ed Closing #212: Panel buttons are reodered on titlebar click.
By default, pekwm will reorder window list on input focus (probably to optimize things) and this would also reorder buttons inside taskbar. Also, on new window list, all panel buttons would be recreated again, causing many allocations and deallocations. Now, window list received from wm is compared agains internal window storage for diffs.

Fixing this issue made removal some old edewm specific code and made panel nicely working under sawfish ;)
2012-12-17 15:49:33 +00:00
Sanel Zukan
9751acdd9e Removing decor from titlebar menus. Fixing some shortcuts so titlebar menus does not appear. 2012-12-06 01:21:12 +00:00
Sanel Zukan
a970841a4f Do not allow running commands from window menu. 2012-12-06 00:37:48 +00:00
Sanel Zukan
804374ebe3 Menu somehow got erased :S. Sanitizing it... 2012-12-06 00:34:36 +00:00
Sanel Zukan
e4d7e831c9 s/struct/class to make clang happy 2012-12-05 15:31:29 +00:00
Sanel Zukan
0cd54534d1 Fixing #205 (Memory applet shows negative swap size).
Fixing bug which is related to memory applet in ede-panel, when swap is used, where negative value was never shown.
2012-12-05 15:14:13 +00:00
Sanel Zukan
6f93f25468 Removing obsolete comment. Small reformatting... 2012-11-26 19:45:46 +00:00
Sanel Zukan
c5fd4cd9ee Fixed #198.
When user logout or shutdown the system, a warning dialog was showing about wrong DBus reply. Now are used
ConsoleKit commands 'CanStop' and 'CanRestart' to check can user perform the action.
2012-11-26 19:38:24 +00:00
Sanel Zukan
b7eb2760dc Clang warnings fix 2012-11-15 03:53:36 +00:00
Sanel Zukan
15dd0b0a80 Added support for receiving notifications.
When issue gets update, reporter can receive mail notifications, but has to have bugzilla account first. The later could not be avoided. Implements #201.
2012-11-07 12:49:43 +00:00
Sanel Zukan
c605359ea1 Space cleanup. 2012-11-02 11:57:11 +00:00
Sanel Zukan
013dfcc481 Removing obsolete efltk rule. 2012-10-23 12:44:36 +00:00
Sanel Zukan
0301585b3c Get FLTK and X versions. 2012-10-23 11:17:30 +00:00
Sanel Zukan
07e43f1c2b Cleanup. 2012-10-23 10:31:27 +00:00
Sanel Zukan
61bd398054 Removing some warning lines. 2012-10-23 10:29:20 +00:00
Sanel Zukan
4e0bd12967 Use also 'edelib-' matcher for debugger invoke. Also, emit PID to ede-crasher for further inspection. 2012-10-23 10:21:34 +00:00
Sanel Zukan
1cc61c1d29 Try to read 'core.PID' if can or fallback on 'core'. 2012-10-23 10:20:21 +00:00
Sanel Zukan
b19a713bdf Use str_hash(). Some cleanup. 2012-10-08 15:40:25 +00:00
Sanel Zukan
c39c0718f9 iconv() is a mess between os-es; const char**, char**,... oh my... 2012-09-24 14:01:08 +00:00
Sanel Zukan
240c195d87 Removing some incomplete code. 2012-09-24 13:48:16 +00:00
Sanel Zukan
5f89e0a412 Required size_t but not visible in sys/utsname.h. Minix again. 2012-09-24 13:46:09 +00:00
Sanel Zukan
599356843b Minix does not have pselect(). This is also good time to refactor xmlrpc-c dependency check in main configure.in script. 2012-09-24 13:43:51 +00:00
Sanel Zukan
c3aa1a61e6 Minix does not have setrlimit(). 2012-09-24 13:20:02 +00:00
Sanel Zukan
c26b526dcd Importing svn2cl as it is used from script that makes release archives.
Making code DBus optional; all DBus related code is wrapped inside EDELIB_HAVE_DBUS.
2012-09-18 17:49:48 +00:00
Sanel Zukan
0ad6617df4 Removing locks. We need better way to determin if FLTK has compiled in locking support or not. 2012-09-03 13:01:34 +00:00
Sanel Zukan
9eca312821 Added missing stdlib.h header. 2012-09-03 13:00:09 +00:00
Sanel Zukan
2d028fe4a6 Let panel taskbar tries to fetch icons of desired size, if possible. Also squashed a small memory leak in keyboard applet. 2012-08-24 14:15:04 +00:00
Sanel Zukan
b4ad2fb11b ifdef-ed some FLTK 1.3.0 specific code. 2012-08-23 02:29:27 +00:00
Sanel Zukan
89ec43af74 Added guards in case autoupdate feature is disabled. 2012-08-06 14:57:20 +00:00
Sanel Zukan
1dde9f92da Menu reload support and clean of some memory leaks.
Menu reload is using DirWatch to monitor application menu folders for changes. With this, any change on some content will trigger
menu update. Update is trying to be safe as possible: when menu is open, a backup menu will be constructed and replaced as soon as menu
was closed; when is closed, it will be directly replaced.

This still can include races, but I'm hoping they will not occur.

Related to memory leaks: on couple of places in cpu applet, delete was wronly called instead delete[]. Also, when ede-panel exits,
AppletManager would not clean loaded apples. Strange. So now explicit clear was added on exit.
2012-08-06 14:52:09 +00:00
Sanel Zukan
a45609e945 Added copyright/legal info. Cleared some deprecation warnings. 2012-08-06 12:00:25 +00:00
Sanel Zukan
705ea3ebf2 Center the window and fixed one spelling issue. 2012-08-05 23:01:11 +00:00
Sanel Zukan
8eeca59484 Made it static. 2012-07-19 08:23:42 +00:00
Sanel Zukan
3ff0844756 Removed some old code causing undefined behavior.
There were leftovers from previous menu version, where icon will be set for certain MenuItem. However, some of those items are removed causing values to be set outside array's bounds. Yuck!
2012-07-19 08:18:36 +00:00
Sanel Zukan
a024e66550 Copyright header and window preservation on mouse enter.
When notification was shown, if given timeout, it can be preserved on screen by entering
with mouse in window area. This can be useful when message with long was shown.
2012-07-17 08:05:52 +00:00
Sanel Zukan
59a16eff0e Fixing panel placement when screen size was changed. Updating main menu to use MenuTooltip code.
When screen dimensions are shrinked, panel will be moved at the correct location but will not be resized correctly. Also,
when screen dimensions are changed again, increasing sizes, panel would not catch that. Here, 'the hack' is to track
root window dimension changes and react on that, since relaying on _NET_WORKAREA is not always good; struts dimentions affects workarea size.

Main menu now has tooltips, which is Comment value from .desktop files. Also, since XdgMenuReader directly plays with MenuItem,
MenuItem::init_extensions() is used to reset uncommon values.
2012-06-07 09:32:27 +00:00
Sanel Zukan
db1ebec5d9 Prevent crashes. Have to investigate further. 2012-06-03 12:29:12 +00:00
Sanel Zukan
39ffa8406b Code cleanup.
Removing usage of EDE_PANEL_APPLET_CLASS since there is no much usage of it. Also, marked all applet widgets as EDE_PANEL_WIDGET_TYPE so panel knows it is widget.

Added license info in some code, but whole ede2 tree needs to be revised for that.
2012-05-30 10:23:27 +00:00
Sanel Zukan
fde927b627 Small cleanup. Added link for ede-notify-daemon docs. 2012-05-28 14:25:53 +00:00
Sanel Zukan
eb175fa89f Moving all class declarations to EDE_PANEL_APPLET_CLASS macro.
This change should make base applet code easier to modify without modifying applets itself. This is also
a starting point for implementation of better routing netwm messages to applets without adding specific listener
to each applet.
2012-05-28 10:57:50 +00:00
Sanel Zukan
9a664ddb92 Cleaning up some warnings. 2012-05-28 10:00:09 +00:00
Sanel Zukan
0d061c24e7 Marked current code as next versionn 2012-05-21 11:29:25 +00:00
116 changed files with 5470 additions and 3564 deletions

View File

@ -129,10 +129,16 @@ X_EXTRA_LIBS ?= @X_EXTRA_LIBS@ ;
# solo XKB extension library
XKB_LIBS ?= @XKB_LIBS@ ;
# shape extension
XSHAPE_LIBS ?= @XSHAPE_LIBS@ ;
# curl libraries
CURL_CFLAGS ?= @CURL_CFLAGS@ ;
CURL_LIBS ?= @CURL_LIBS@ ;
# kstat
KSTAT_LIBS ?= @KSTAT_LIBS@ ;
# platform specific pthread flags
# FIXME: a quick hack to work everything on SunStudio
if $(SUN_COMPILER) {

View File

@ -10,7 +10,7 @@
SubDir TOP ;
EdeManualWithToc README ;
# EdeManualWithToc README ;
Clean distclean : $(JCACHEFILE) $(HCACHEFILE) ;
@ -31,7 +31,6 @@ SubInclude TOP ede-screen-lock ;
SubInclude TOP ede-help ;
SubInclude TOP ede-image-view ;
SubInclude TOP ede-launch ;
SubInclude TOP emountd ;
SubInclude TOP ede-timedate ;
SubInclude TOP ede-tip ;
SubInclude TOP ede-preferred-applications ;

58
README
View File

@ -1,58 +0,0 @@
Readme for EDE
==============
Thank you for showing interest in EDE project. EDE is small and fast desktop environment
that uses http://www.fltk.org[FLTK Toolkit]. For more details and philosophy behind it, check
http://equinox-project.org/wiki/AboutEde[about EDE on our wiki].
As every software project, EDE is always in development so your contribution is always welcome!
Build requirements
------------------
EDE is using FLTK toolkit from http://www.fltk.org[www.fltk.org]. At the time
of this writing, latest stable tree is 1.3.x.
Since FLTK lacks many things needed for developing a full *nix desktop
environment, we have developed a small add-on library called 'edelib'. This
library is also required for compiling EDE and is released together with EDE.
We *strongly* recommend that you use matching versions of EDE and
edelib (e.g. released at the same time) or you make repository checkout at the same time due
their frequent changes.
Also you will need a 'jam' tool. Jam is a make replacement and you will find it on our repository.
Downloading the code
--------------------
The best way to download latest code is checking it out from our repository. These modules
you should checkout (with their paths):
- jam : 'svn co https://ede.svn.sourceforge.net/svnroot/ede/trunk/jam'
- edelib : 'svn co https://ede.svn.sourceforge.net/svnroot/ede/trunk/edelib'
- ede : 'svn co https://ede.svn.sourceforge.net/svnroot/ede/trunk/ede2'
If you already have Jam installed, there is no need to download it.
Compiling and installing
------------------------
In order to build and install EDE do the following steps:
1. compile and install jam first; going to jam source directory and running 'make' will do
the job; after that you should get 'bin.YOUR_PLATFORM' directory (on Linux it will be
bin.linux) and copy 'jam' executable in your $PATH, e.g. /usr/local/bin
2. compile and install edelib; please read README file in edelib directory
3. go in ede2 directory and run './autogen.sh'
4. after that, goes './configure --enable-debug'
5. jam
6. jam install
Please note how this document is quick and short tutorial about EDE installation. For more details,
please check http://equinox-project.org/wiki/InstallationHowTo[Installation Howto] on our wiki.

58
README.md Normal file
View File

@ -0,0 +1,58 @@
# EDE
EDE, the `Equinox Desktop Environment`, is a small and fast desktop
environment that uses the [FLTK toolkit](http://www.fltk.org).
For more details and the philosophy behind it, see
[about EDE on our wiki](http://equinox-project.org/wiki/AboutEde).
## Build requirements
EDE requires FLTK; at the time of this writing, the latest stable
branch is 1.3.x.
Since FLTK lacks many things needed for developing a full *nix desktop
environment, we have developed a small add-on library called
`edelib`. This library is needed both for building and running the
desktop. Edelib is developed and released together with EDE.
It is *strongly* recommended to use matching versions of EDE and
edelib (i.e. versions released at the same time) or to checkout
both from the repository at the same time to make sure they work
together well.
Also you will need the `jam` tool. Jam is a *make* replacement and you
can find it on our repository.
## Downloading the code
The best way to get the latest code is checking it out from our
repository. These are the modules you should checkout (with their paths):
- *jam* - `git clone https://github.com/edeproject/jam.git`
- *edelib* - `git clone https://github.com/edeproject/edelib.git`
- *ede* - `git clone https://github.com/edeproject/ede.git`
If you already have Jam installed, there is of course no need to download
it again. Either vanilla Jam or FTJam can be used to build EDE. Boost Jam is
known to *not* work.
## Compiling and installing
In order to build and install EDE do the following steps:
1. compile and install `jam` first; going to jam source directory and running `make` will do
the job; after that you should get `bin.YOUR_PLATFORM` directory (e.g. on Linux it will be
bin.linux) and copy `jam` executable in your $PATH, e.g. */usr/local/bin*
2. compile and install `edelib`; please read README file in edelib directory
3. change into the ede directory and run `./autogen.sh`
4. after that, do `./configure --enable-debug`
5. jam
6. jam install
Please note that this document is only a quick and short tutorial on installing EDE. For more details
please see [Installation Howto](http://equinox-project.org/wiki/InstallationHowTo) on our wiki.

View File

@ -109,26 +109,6 @@ rule EdeProgramAsFltkBare
}
}
# EfltkProgram [target] : [sources] : [noinstall] ;
# Creates programs that will be linked with efltk. If [noinstall] is given,
# [target] will not be installed wit 'jam install'.
rule EfltkProgram
{
if ! $(EFLTKINCLUDE) || ! $(EFLTKLIB) {
Echo "EFLTKINCLUDE or EFLTKLIB not defined; $(1) will not be built" ;
return ;
}
MakeProgramPrivate $(1) : $(2)
: $(EFLTKLIB) $(STDLIB)
: $(GLOBALFLAGS) $(EFLTKINCLUDE) ;
# install it where ede binaries resides
if $(3) != "noinstall" {
InstallEdeProgram $(1) ;
}
}
# FltkProgram [target] : [sources] : [noinstall] ;
# Creates programs that will be linked with fltk only. It will use full fltk
# dependencies (images).

View File

@ -8,7 +8,7 @@
# GNU General Public License version 2 or newer.
# See COPYING for details.
SVG_CONVERTOR = "rsvg" ;
SVG_CONVERTOR = "rsvg-convert" ;
# SvgToPng [target-png] : [source-svg] : [width] : [height] ;
rule SvgToPng

View File

@ -2,14 +2,14 @@ dnl
dnl $Id: configure.in 1719 2006-08-15 08:56:42Z karijes $
dnl
dnl Part of Equinox Desktop Environment (EDE).
dnl Copyright (c) 2000-2012 EDE Authors.
dnl Copyright (c) 2000-2014 EDE Authors.
dnl
dnl This program is licenced under terms of the
dnl GNU General Public Licence version 2 or newer.
dnl See COPYING for details.
m4_define([ede_major_version], [2])
m4_define([ede_minor_version], [0])
m4_define([ede_minor_version], [2])
m4_define([ede_patch_version], [0])
m4_define([ede_version], [ede_major_version.ede_minor_version.ede_patch_version])
@ -56,6 +56,17 @@ AC_PATH_XTRA
AC_HEADER_STDC
dnl for xmlrpc-c
AC_CHECK_FUNC(pselect, AC_DEFINE(HAVE_PSELECT, 1, [Define to 1 if you have pselect()]))
AC_CHECK_FUNC(setgroups, AC_DEFINE(HAVE_SETGROUPS, 1, [Define to 1 if you have setgroups()]))
AC_CHECK_FUNC(asprintf, AC_DEFINE(HAVE_ASPRINTF, 1, [Define to 1 if you have asprintf()]))
AC_CHECK_FUNC(setenv, AC_DEFINE(HAVE_SETENV, 1, [Define to 1 if you have setenv()]))
AC_CHECK_FUNC(wcsncmp, AC_DEFINE(HAVE_WCSNCMP, 1, [Define to 1 if you have wcsncmp()]))
AC_CHECK_FUNC(gettimeofday, AC_DEFINE(HAVE_GETTIMEOFDAY, 1, [Define to 1 if you have gettimeofday()]))
AC_CHECK_FUNC(localtime_r, AC_DEFINE(HAVE_LOCALTIME_R, 1, [Define to 1 if you have localtime_r()]))
AC_CHECK_FUNC(gmtime_r, AC_DEFINE(HAVE_GMTIME_R, 1, [Define to 1 if you have gmtime_r()]))
AC_CHECK_FUNC(strcasecmp, AC_DEFINE(HAVE_STRCASECMP, 1, [Define to 1 if you have strcasecmp()]))
if test "$enable_profile" = "yes"; then
enable_debug=yes
fi
@ -78,6 +89,7 @@ if test "$enable_shape" = "yes"; then
if test "$have_xshape" = "yes"; then
AC_DEFINE(HAVE_SHAPE, 1, [Define to 1 if you have XShape extension])
XSHAPE_LIBS="-lXext"
fi
fi
@ -106,10 +118,7 @@ else
fi
if test -n "$with_edelib_path"; then
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_edelib_path"
else
dnl TODO: remove this in release
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/opt/ede/lib/pkgconfig"
export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_edelib_path/lib/pkgconfig"
fi
PKG_CHECK_MODULES(EDELIB, [edelib],, [have_edelib=no])
@ -129,7 +138,7 @@ fi
PKG_CHECK_MODULES(EDELIB_DBUS, [edelib-dbus],, [have_edelib_dbus=no])
if test "$have_edelib_dbus" = "no"; then
AC_MSG_ERROR(edelib-dbus not found! You must install it first)
AC_MSG_RESULT(edelib is compiled without DBus so EDE will be compiled without DBus support)
fi
dnl find edelib documentation
@ -249,6 +258,30 @@ else
AC_MSG_RESULT(no)
fi
dnl kstat/solaris
AC_CHECK_HEADER(kstat.h, [have_kstat_h=yes],)
if test "x$have_kstat_h" = "xyes"; then
AC_MSG_CHECKING([for kstat presence])
AC_LANG_SAVE
AC_LANG_C
AC_TRY_COMPILE([
#include <kstat.h>
],[
kstat_named_t k;
k.value.ui32;
],[have_kstat=yes],[])
AC_LANG_RESTORE
if test "x$have_kstat" = "xyes"; then
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_KSTAT, 1, [Define to 1 if you have kstat])
KSTAT_LIBS=" -lkstat"
else
AC_MSG_RESULT(no)
fi
fi
dnl pekwm specific macros
EDE_CHECK_PEKWM_DEPENDENCIES
@ -268,7 +301,9 @@ AC_SUBST(CURL_CFLAGS)
AC_SUBST(CURL_LIBS)
AC_SUBST(LARGEFILE)
AC_SUBST(XKB_LIBS)
AC_SUBST(XSHAPE_LIBS)
AC_SUBST(my_sysconfdir)
AC_SUBST(KSTAT_LIBS)
AC_SUBST(PEKWM_CXXFLAGS)
AC_SUBST(PEKWM_LIBS)

View File

@ -20,10 +20,10 @@ Global {
KeyPress = "Mod4 Up" { Actions = "FocusDirectional Up" }
KeyPress = "Mod4 Down" { Actions = "FocusDirectional Down" }
# Moving in workspaces
KeyPress = "Ctrl Mod1 Left" { Actions = "GotoWorkspace Left" }
KeyPress = "Ctrl Mod1 Right" { Actions = "GotoWorkspace Right" }
KeyPress = "Ctrl Mod1 Up" { Actions = "GotoWorkspace Up" }
KeyPress = "Ctrl Mod1 Down" { Actions = "GotoWorkspace Down" }
KeyPress = "Ctrl Mod1 Left" { Actions = "HideAllMenus; GotoWorkspace Left" }
KeyPress = "Ctrl Mod1 Right" { Actions = "HideAllMenus; GotoWorkspace Right" }
KeyPress = "Ctrl Mod1 Up" { Actions = "HideAllMenus; GotoWorkspace Up" }
KeyPress = "Ctrl Mod1 Down" { Actions = "HideAllMenus; GotoWorkspace Down" }
KeyPress = "Mod4 1" { Actions = "GotoWorkspace 1" }
KeyPress = "Mod4 2" { Actions = "GotoWorkspace 2" }
KeyPress = "Mod4 3" { Actions = "GotoWorkspace 3" }

View File

@ -2,3 +2,49 @@
# Variables
INCLUDE = "vars"
WindowMenu = "Window Menu" {
Entry = "(Un)Stick" { Actions = "Toggle Sticky" }
Entry = "(Un)Shade" { Actions = "Toggle Shaded" }
Entry = "Iconify" { Actions = "Set Iconified" }
Submenu = "Maximize" {
Entry = "Toggle Full" { Actions = "Toggle Maximized True True" }
Entry = "Toggle Horizontal" { Actions = "Toggle Maximized True False" }
Entry = "Toggle Vertical" { Actions = "Toggle Maximized False True" }
}
Submenu = "Fill" {
Entry = "Full" { Actions = "MaxFill True True" }
Entry = "Horizontal" { Actions = "MaxFill True False" }
Entry = "Vertical" { Actions = "MaxFill False True" }
}
Submenu = "Stacking" {
Entry = "Raise" { Actions = "Raise" }
Entry = "Lower" { Actions = "Lower" }
Entry = "Toggle Always On Top" { Actions = "Toggle AlwaysOnTop" }
Entry = "Toggle Always Below" { Actions = "Toggle AlwaysBelow" }
}
Submenu = "Decorations" {
Entry = "Toggle Decorations" { Actions = "Toggle DecorBorder; Toggle DecorTitlebar" }
Entry = "Toggle Borders" { Actions = "Toggle DecorBorder" }
Entry = "Toggle Titlebar" { Actions = "Toggle DecorTitlebar" }
}
Submenu = "Skip" {
Entry = "Toggle showing this frame in menus" { Actions = "Toggle Skip Menus" }
Entry = "Toggle including this frame in focus toggle" { Actions = "Toggle Skip FocusToggle" }
Entry = "Toggle if this frame snaps to other windows" { Actions = "Toggle Skip Snap" }
}
SubMenu = "Send To" {
# Create sendto menu once per pekwm config reload. The fast way that
# will work for most if not all users.
COMMAND = "$_PEKWM_SCRIPT_PATH/pekwm_ws_menu.sh send"
# Create sendto menu every time the menu is opened. The slow way.
# This is what you want if you are using external tools to make
# the amount of workspaces something else than what you define in
# ~/.pekwm/config. You will know if you want this.
# Entry = "" { Actions = "Dynamic $_PEKWM_SCRIPT_PATH/pekwm_ws_menu.sh send dynamic" }
}
Separator {}
Entry = "Close" { Actions = "Close" }
Submenu = "Kill" { Entry = "Kill application" { Actions = "Kill" } }
}

View File

@ -1,10 +1,10 @@
FrameTitle {
ButtonRelease = "1" { Actions = "Raise; Focus; ActivateClient" }
ButtonRelease = "1" { Actions = "HideAllMenus; Raise; Focus; ActivateClient" }
ButtonRelease = "Mod1 1" { Actions = "Focus; Raise" }
ButtonRelease = "Mod4 1" { Actions = "Focus; Raise" }
ButtonRelease = "2" { Actions = "ActivateClient" }
ButtonRelease = "Mod4 3" { Actions = "Close" }
ButtonRelease = "3" { Actions = "ShowMenu Window" }
ButtonRelease = "3" { Actions = "HideAllMenus; ShowMenu Window" }
ButtonRelease = "4" { Actions = "ActivateClientRel 1" }
ButtonRelease = "5" { Actions = "ActivateClientRel -1" }
ButtonRelease = "Mod1 4" { Actions = "SendToWorkspace Next; GotoWorkspace Next" }
@ -16,8 +16,8 @@ FrameTitle {
ButtonRelease = "Ctrl Mod1 1" { Actions = "Focus; Raise True" }
DoubleClick = "2" { Actions = "Toggle Shaded" }
DoubleClick = "Mod1 2" { Actions = "Toggle Shaded" }
DoubleClick = "1" { Actions = "MaxFill True True" }
DoubleClick = "Mod1 1" { Actions = "Toggle Maximized True True" }
DoubleClick = "1" { Actions = "Toggle Maximized True True" }
DoubleClick = "Mod1 1" { Actions = "Toggle MaxFill True True" }
Motion = "1" { Threshold = "4"; Actions = "Raise; Move" }
Motion = "Mod1 1" { Threshold = "4"; Actions = "Raise; Move" }
Motion = "Mod4 1" { Threshold = "4"; Actions = "Raise; Move" }
@ -135,7 +135,7 @@ Client {
# Remove the following line and uncomment the alternative if windows should raise when clicked.
#ButtonPress = "1" { Actions = "Focus" }
# Uncomment the following line if windows should raise when clicked.
ButtonPress = "1" { Actions = "Focus; Raise" }
ButtonPress = "1" { Actions = "HideAllMenus; Focus; Raise" }
ButtonRelease = "Mod1 1" { Actions = "Focus; Raise" }
ButtonRelease = "Mod4 1" { Actions = "Lower" }

View File

@ -10,4 +10,4 @@
SubDir TOP data pekwm scripts ;
InstallProgram "$(PEKWM_DATA_DIR)/scripts" : pekwm_themeset.sh pekwm_ws_menu.sh ;
# InstallProgram "$(PEKWM_DATA_DIR)/scripts" : pekwm_themeset.sh pekwm_ws_menu.sh ;

View File

@ -154,7 +154,7 @@ PDecor {
Decor = "Menu" {
Title {
@DecorBase
@DecorEmpty
@DecorBorder
}
}

View File

@ -3,7 +3,7 @@
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2007-2009 EDE Authors.
# Copyright (c) 2007-2013 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
@ -41,6 +41,8 @@ if [ "x$XDG_MENU_PREFIX" = "x" ]; then
XDG_MENU_PREFIX="ede-"
fi
XDG_CURRENT_DESKTOP="EDE"
[ -d $XDG_DATA_HOME ] || mkdir -p $XDG_DATA_HOME
[ -d $XDG_CONFIG_HOME ] || mkdir -p $XDG_CONFIG_HOME
[ -d $XDG_CACHE_HOME ] || mkdir -p $XDG_CACHE_HOME
@ -51,25 +53,14 @@ export XDG_CACHE_HOME
export XDG_DATA_DIRS
export XDG_CONFIG_DIRS
export XDG_MENU_PREFIX
export XDG_CURRENT_DESKTOP
PATH=$PATH:$PREFIX:$PREFIX/bin
export PATH
userresources=$HOME/.Xdefaults
sysresources=/usr/X11R6/lib/X11/xinit/.Xresources
if [ -f $sysresources ]; then
xrdb -merge $sysresources
fi
if [ -f $userresources ]; then
xrdb -merge $userresources
fi
# set background inside X
XSETROOT=`which xsetroot 2> /dev/null`
if [ "$XSETROOT" ]; then
$XSETROOT -solid black
# set the background color inside X
if command -v xsetroot > /dev/null 2>&1; then
xsetroot -solid black
fi
# remove leftovers if evoke crashed

View File

@ -1,21 +1,6 @@
/////////////////////////////////////////////////
From this file is generated index.html
and is placed in 'manual' directory.
Also rest of the html files are generated
from various places in the tree and put
in 'manual' too.
Knowing this, url links should point in
local directory, not 'manual'.
Before doing _any_ changes, consulting asciidoc
documentation about tags and usage will be applauded.
/////////////////////////////////////////////////
{edeversion} manual
{edeversion} manual
===================
:Revision: 0.1
:Revision: 0.2
*Introduction*
@ -28,7 +13,7 @@
- link:ede-help.html[ede-help]
- link:ede-tip.html[ede-tip]
- link:evoke.html[evoke]
- link:emountd.html[emountd]
- link:ede-notify-daemon.html[ede-notify-daemon]
*Development*

View File

@ -3,7 +3,7 @@
*
* Eabout, display version and authors
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2008-2012 EDE Authors.
* Copyright (c) 2008-2014 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
@ -102,11 +102,11 @@ const char* bold_keywords[] = {
#define BOLD_KEYWORDS_LEN 8
void close_cb(Fl_Widget*, void*) {
static void close_cb(Fl_Widget*, void*) {
win->hide();
}
char* prepare_style(char* txt, int len) {
static char* prepare_style(char* txt, int len) {
// paint all with 'A' style at startup
char* style = new char[len + 1];
memset(style, 'A', len - 1);
@ -114,12 +114,13 @@ char* prepare_style(char* txt, int len) {
// find bold keywords and paint them
char* p = 0;
unsigned int ln;
for(int i = 0; i < BOLD_KEYWORDS_LEN; i++) {
p = strstr(txt, bold_keywords[i]);
if(!p)
continue;
unsigned int len = strlen(bold_keywords[i]);
memset(&style[p - txt], 'B', len);
if(!p) continue;
ln = strlen(bold_keywords[i]);
memset(&style[p - txt], 'B', ln);
}
return style;
@ -141,7 +142,7 @@ int main(int argc, char **argv) {
ede_label_box->labelfont(1);
ede_label_box->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE);
Fl_Box* ede_copy_box = new Fl_Box(70, 35, 300, 25, "Copyright (c) by EDE Authors 2000-2012");
Fl_Box* ede_copy_box = new Fl_Box(70, 35, 300, 25, "Copyright (c) by EDE Authors 2000-2014");
ede_copy_box->labelsize(11);
ede_copy_box->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_TOP);

View File

@ -19,6 +19,7 @@
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <FL/Fl.H>
#include <FL/Fl_Check_Browser.H>
@ -41,7 +42,7 @@
#include <edelib/Ede.h>
EDELIB_NS_USING_AS(Window, AppWindow)
EDELIB_NS_USING_LIST(15, (String,
EDELIB_NS_USING_LIST(17, (String,
DesktopFile,
IconLoader,
list,
@ -49,8 +50,10 @@ EDELIB_NS_USING_LIST(15, (String,
system_config_dirs,
user_config_dir,
str_ends,
str_tolower,
run_async,
ask,
alert,
file_test,
window_center_on_screen,
FILE_TEST_IS_REGULAR,
@ -135,8 +138,8 @@ static void unique_by_basename(StringList& lst) {
}
static void entry_list_run_clear(DialogEntryList& l, bool run) {
DialogEntryListIter dit = l.begin(), dit_end = l.end();
for(; dit != dit_end; ++dit) {
DialogEntryListIter dit = l.begin(), dite = l.end();
for(; dit != dite; ++dit) {
if(run)
AUTOSTART_RUN((*dit)->exec.c_str());
delete *dit;
@ -188,8 +191,8 @@ static void run_autostart_dialog(DialogEntryList& l) {
txt->align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_WRAP);
cbrowser = new Fl_Check_Browser(10, 75, 350, 185);
DialogEntryListIter it = l.begin(), it_end = l.end();
for(; it != it_end; ++it) {
DialogEntryListIter it = l.begin(), ite = l.end();
for(; it != ite; ++it) {
if((*it)->comment.empty())
cbrowser->add((*it)->name.c_str());
else {
@ -222,13 +225,13 @@ static void perform_autostart(bool safe) {
adir += AUTOSTART_DIRNAME;
StringList dfiles, sysdirs, tmp;
StringListIter it, it_end, tmp_it, tmp_it_end;
StringListIter it, ite, tmp_it, tmp_ite;
dir_list(adir.c_str(), dfiles, true);
system_config_dirs(sysdirs);
if(!sysdirs.empty()) {
for(it = sysdirs.begin(), it_end = sysdirs.end(); it != it_end; ++it) {
for(it = sysdirs.begin(), ite = sysdirs.end(); it != ite; ++it) {
*it += AUTOSTART_DIRNAME;
/*
@ -237,22 +240,18 @@ static void perform_autostart(bool safe) {
* probably via merge() member
*/
dir_list((*it).c_str(), tmp, true);
for(tmp_it = tmp.begin(), tmp_it_end = tmp.end(); tmp_it != tmp_it_end; ++tmp_it)
for(tmp_it = tmp.begin(), tmp_ite = tmp.end(); tmp_it != tmp_ite; ++tmp_it)
dfiles.push_back(*tmp_it);
}
}
if(dfiles.empty())
return;
if(dfiles.empty()) return;
/*
* Remove duplicates where first one seen have priority to be keept.
* This way is required by spec.
* Remove duplicates where first one seen have priority to be keept. This way is required by spec.
*
* Also handle this case (noted in spec):
* if $XDG_CONFIG_HOME/autostart/foo.desktop and $XDG_CONFIG_DIRS/autostart/foo.desktop
* exists, but $XDG_CONFIG_HOME/autostart/foo.desktop have 'Hidden = true',
* $XDG_CONFIG_DIRS/autostart/foo.autostart is ignored too.
* Also handle this case (noted in spec): * if $XDG_CONFIG_HOME/autostart/foo.desktop and $XDG_CONFIG_DIRS/autostart/foo.desktop
* exists, but $XDG_CONFIG_HOME/autostart/foo.desktop have 'Hidden = true', * $XDG_CONFIG_DIRS/autostart/foo.autostart is ignored too.
*
* Later is implied via unique_by_basename().
*/
@ -263,7 +262,7 @@ static void perform_autostart(bool safe) {
DesktopFile df;
DialogEntryList entry_list;
for(it = dfiles.begin(), it_end = dfiles.end(); it != it_end; ++it) {
for(it = dfiles.begin(), ite = dfiles.end(); it != ite; ++it) {
if((*it).empty())
continue;
@ -276,12 +275,23 @@ static void perform_autostart(bool safe) {
E_WARNING(E_STRLOC ": Can't load '%s'. Skipping...\n", name);
continue;
}
/* obey to OnlyShowIn rule */
if(df.only_show_in(buf, sizeof(buf))) {
str_tolower((unsigned char*)buf);
if(strstr(buf, "ede") == NULL)
continue;
}
/* obey to NotShowIn rule */
if(df.not_show_in(buf, sizeof(buf))) {
str_tolower((unsigned char*)buf);
if(strstr(buf, "ede") != NULL)
continue;
}
/* files marked as hidden must be skipped */
if(df.hidden())
continue;
if(!df.exec(buf, sizeof(buf)))
if(df.hidden() || !df.exec(buf, sizeof(buf)))
continue;
DialogEntry* en = new DialogEntry;
@ -321,8 +331,11 @@ static void perform_autostart_scripts(const char* dir) {
"Would you like to start them?"), dir))
{
/* spec said how we must chdir to the root of the medium */
chdir(dir);
AUTOSTART_RUN(path);
errno = 0;
if(chdir(dir) == 0)
AUTOSTART_RUN(path);
else
alert(_("Unable to change folder: %s"), strerror(errno));
}
/* we only match the one file */

View File

@ -28,14 +28,18 @@ struct BugzillaData {
xmlrpc_env xenv;
xmlrpc_client *xcli;
String url;
BugzillaErrorCallback cb;
void *cb_data;
};
BugzillaData *bugzilla_new(const char *u) {
BugzillaData *bugzilla_new(const char *url, BugzillaErrorCallback cb, void *cb_data) {
BugzillaData *data = new BugzillaData;
bugzilla_set_error_callback(data, cb, cb_data);
xmlrpc_env_init(&data->xenv);
xmlrpc_client_setup_global_const(&data->xenv);
data->url = u;
data->url = url;
/*
* to allow https connections; curl by default refuse connections without valid certificate
@ -51,6 +55,7 @@ BugzillaData *bugzilla_new(const char *u) {
xmlrpc_client_create(&data->xenv, XMLRPC_CLIENT_NO_FLAGS, "ede-bug-report", "0.1", &gparms, sizeof(gparms), &data->xcli);
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to init xmlrpc client data (%s)\n", data->xenv.fault_string);
if(cb) cb(data->xenv.fault_string, cb_data);
delete data;
data = NULL;
}
@ -68,6 +73,12 @@ void bugzilla_free(BugzillaData *data) {
delete data;
}
void bugzilla_set_error_callback(BugzillaData *data, BugzillaErrorCallback cb, void *cb_data) {
E_ASSERT(data != NULL);
data->cb = cb;
data->cb_data = cb_data;
}
char *bugzilla_get_version(BugzillaData *data) {
E_ASSERT(data != NULL);
@ -76,12 +87,12 @@ char *bugzilla_get_version(BugzillaData *data) {
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to call xmlrpc function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return (char*)"";
}
/* this value will be malloc()-ated by xmlrpc_decompose_value() and should be freeed by user */
char *ret;
xmlrpc_decompose_value(&data->xenv, result, "{s:s,*}", "version", &ret);
xmlrpc_DECREF(result);
@ -103,6 +114,7 @@ int bugzilla_login(BugzillaData *data, const char *user, const char *passwd) {
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to perform login function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return id;
}
@ -120,41 +132,70 @@ void bugzilla_logout(BugzillaData *data) {
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to call xmlrpc function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return;
}
xmlrpc_DECREF(result);
}
int bugzilla_submit_bug(BugzillaData *data, const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity)
int bugzilla_submit_bug(BugzillaData *data,
const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity,
const char *cc)
{
E_ASSERT(data != NULL);
int bug_id = -1;
xmlrpc_value *result;
xmlrpc_client_call2f(&data->xenv, data->xcli, data->url.c_str(), "Bug.create", &result,
"({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
"product", product,
"component", component,
"summary", summary,
"version", version,
"description", description,
"op_sys", op_sys,
"platform", platform,
"priority", priority,
"severity", severity);
/* if given CC, add it so bugzilla assign that email as notification receiver */
if(cc) {
/* as for now we only support single email address */
xmlrpc_value *cc_array, *cc_str;
cc_array = xmlrpc_array_new(&data->xenv);
cc_str = xmlrpc_string_new(&data->xenv, (const char *const)cc);
xmlrpc_array_append_item(&data->xenv, cc_array, cc_str);
xmlrpc_DECREF(cc_str);
xmlrpc_client_call2f(&data->xenv, data->xcli, data->url.c_str(), "Bug.create", &result,
"({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:A})",
"product", product,
"component", component,
"summary", summary,
"version", version,
"description", description,
"op_sys", op_sys,
"platform", platform,
"priority", priority,
"severity", severity,
"cc", cc_array);
xmlrpc_DECREF(cc_array);
} else {
xmlrpc_client_call2f(&data->xenv, data->xcli, data->url.c_str(), "Bug.create", &result,
"({s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
"product", product,
"component", component,
"summary", summary,
"version", version,
"description", description,
"op_sys", op_sys,
"platform", platform,
"priority", priority,
"severity", severity);
}
if(data->xenv.fault_occurred) {
E_WARNING(E_STRLOC ": Unable to perform submit function (%s)\n", data->xenv.fault_string);
if(data->cb) (data->cb)(data->xenv.fault_string, data->cb_data);
return bug_id;
}

View File

@ -14,9 +14,11 @@
#define __BUGZILLA_H__
struct BugzillaData;
typedef void (*BugzillaErrorCallback)(const char *str, void *data);
BugzillaData *bugzilla_new(const char *url);
BugzillaData *bugzilla_new(const char *url, BugzillaErrorCallback cb = NULL, void *data = NULL);
void bugzilla_free(BugzillaData *data);
void bugzilla_set_error_callback(BugzillaData *data, BugzillaErrorCallback cb, void *cb_data = NULL);
/* return bugzilla version or empty string if fails; returned value must be free()-ed */
char *bugzilla_get_version(BugzillaData *data);
@ -26,13 +28,15 @@ int bugzilla_login(BugzillaData *data, const char *user, const char *
void bugzilla_logout(BugzillaData *data);
/* return bug id or -1 if fails */
int bugzilla_submit_bug(BugzillaData *data, const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity);
int bugzilla_submit_bug(BugzillaData *data,
const char *product,
const char *component,
const char *summary,
const char *version,
const char *description,
const char *op_sys,
const char *platform,
const char *priority,
const char *severity,
const char *cc);
#endif

View File

@ -27,10 +27,10 @@
#include <edelib/String.h>
#include "PulseProgress.h"
#include "BugzillaSender.h"
#include "Bugzilla.h"
#include "BugzillaSender.h"
#define EDE_BUGZILLA_XMLRPC_URL "http://bugs.equinox-project.org/xmlrpc.cgi"
#define EDE_BUGZILLA_XMLRPC_URL "http://bugs.equinox-project.org/xmlrpc.cgi"
/* must match to existing user */
#define EDE_BUGZILLA_USER "ede-bugs@lists.sourceforge.net"
@ -49,6 +49,7 @@ EDELIB_NS_USING(String)
struct BugContent {
const char *bug_title;
const char *bug_content;
const char *bug_sender;
};
static Fl_Double_Window *win;
@ -176,13 +177,13 @@ static void* thread_worker(void *d) {
goto done;
}
/* wait some time if user decided to press 'Cancel' */
sleep(1);
pthread_mutex_lock(&runner_mutex);
should_cancel = cancel_sending;
pthread_mutex_unlock(&runner_mutex);
/* allow user to cancel it */
sleep(1);
if(should_cancel) {
write_string(report_pipe[1], "CANCELED");
goto done;
@ -190,18 +191,18 @@ static void* thread_worker(void *d) {
write_string(report_pipe[1], _("Submitting the report..."));
ret = bugzilla_submit_bug(bdata,
"ede",
"general",
data->bug_title,
"unspecified",
data->bug_content,
"All",
"All",
"P5",
"normal");
"ede",
"general",
data->bug_title,
"unspecified",
data->bug_content,
"All",
"All",
"P5",
"normal",
data->bug_sender);
if(ret == -1) {
write_string_fail(report_pipe[1], _("Unable to properly submit the data. Please try again"));
write_string_fail(report_pipe[1], _("Unable to send the data. Either your email address is not registered on EDE Tracker or the host is temporarily down"));
goto done;
}
@ -214,11 +215,11 @@ done:
delete data;
pthread_exit(NULL);
/* shutup compiler */
/* shutup the compiler */
return NULL;
}
static void perform_send(const char *title, const char *content) {
static void perform_send(const char *title, const char *content, const char *sender) {
pthread_t thread;
/*
@ -228,6 +229,7 @@ static void perform_send(const char *title, const char *content) {
BugContent *c = new BugContent;
c->bug_title = title;
c->bug_content = content;
c->bug_sender = sender;
/* Create joinable thread. Some implementations prefer this explicitly was set. */
pthread_attr_t attr;
@ -244,33 +246,36 @@ static void perform_send(const char *title, const char *content) {
pthread_attr_destroy(&attr);
}
bool bugzilla_send_with_progress(const char *title, const char *content) {
bool bugzilla_send_with_progress(const char *title, const char *content, const char *cc) {
data_submitted = false;
cancel_sending = false;
bdata = bugzilla_new(EDE_BUGZILLA_XMLRPC_URL);
if(!bdata) {
alert(_("Unable to initialize bugzilla interface!"));
return false;
}
/* setup communication as soon as possible */
if(pipe(report_pipe) != 0) {
alert(_("Unable to initialize communication pipe"));
return false;
}
/* prepare mutex */
pthread_mutex_init(&runner_mutex, NULL);
Fl_Button *cancel;
/* register our callback on pipe */
Fl::add_fd(report_pipe[0], FL_READ, report_pipe_cb);
bdata = bugzilla_new(EDE_BUGZILLA_XMLRPC_URL);
if(!bdata) {
alert(_("Unable to initialize bugzilla interface!"));
goto send_done;
}
/* prepare mutex */
pthread_mutex_init(&runner_mutex, NULL);
win = new Fl_Double_Window(275, 90, _("Sending report data"));
win->begin();
progress = new PulseProgress(10, 20, 255, 25, _("Sending report..."));
progress->selection_color((Fl_Color)137);
Fl_Button *cancel = new Fl_Button(175, 55, 90, 25, _("&Cancel"));
cancel = new Fl_Button(175, 55, 90, 25, _("&Cancel"));
cancel->callback(cancel_cb);
win->end();
@ -280,17 +285,18 @@ bool bugzilla_send_with_progress(const char *title, const char *content) {
progress->label(_("Preparing data..."));
Fl::add_timeout(PROGRESS_STEP_REFRESH, progress_timeout);
perform_send(title, content);
perform_send(title, content, cc);
while(win->shown())
Fl::wait();
pthread_mutex_destroy(&runner_mutex);
send_done:
/* clear pipe callback */
Fl::remove_fd(report_pipe[0]);
clear_timeouts();
pthread_mutex_destroy(&runner_mutex);
close(report_pipe[0]);
close(report_pipe[1]);

View File

@ -13,6 +13,8 @@
#ifndef __BUGZILLASENDER_H__
#define __BUGZILLASENDER_H__
bool bugzilla_send_with_progress(const char *title, const char *content);
bool bugzilla_send_with_progress(const char *title,
const char *content,
const char *cc);
#endif

View File

@ -50,16 +50,20 @@ if $(CURL_CFLAGS) || $(CURL_LIBS) {
$(PTHREAD_CFLAGS)
$(PTHREAD_LIBS) ;
MkDir $(XMLRPC_C_LIB_DIR) ;
# xmlrpc-c related builds
rule XmlrpcLibrary {
local lib = [ FDirName $(XMLRPC_C_LIB_DIR) $(<) ] ;
local libe = $(lib:S=$(SUFLIB)) ;
# compile it with OPTIMFLAGS got from top Jamconfig
ObjectCcFlags $(>) : $(XMLRPC_C_FLAGS) $(OPTIMFLAGS) ;
StaticLibrary $(lib) : $(>) ;
LocalDepends $(libe) : $(XMLRPC_C_LIB_DIR) ;
# make sure libraries are build first
LocalDepends $(BINARY) : $(lib:S=$(SUFLIB)) ;
LocalDepends $(BINARY) : $(libe) ;
}
SEARCH_SOURCE += [ FDirName $(XMLRPC_C_SRC_PATH) src ] ;
@ -99,7 +103,7 @@ if $(CURL_CFLAGS) || $(CURL_LIBS) {
curlmulti.c
lock_pthread.c ;
ObjectCcFlags $(CURL_TRANSPORT_SRC) : $(CURL_CFLAGS) ;
ObjectCcFlags $(CURL_TRANSPORT_SRC) : $(XMLRPC_C_FLAGS) $(CURL_CFLAGS) ;
UTIL_SRC =
casprintf.c

View File

@ -43,7 +43,7 @@ void PulseProgress::draw(void) {
draw_box(box(), x(), y(), w(), h(), color());
fl_clip(xoff, yoff, woff, hoff);
fl_push_clip(xoff, yoff, woff, hoff);
Fl_Color c = fl_color();
fl_color(color2());
@ -63,6 +63,7 @@ void PulseProgress::draw(void) {
fl_color(c);
fl_pop_clip();
labelcolor(fl_contrast(labelcolor(), color()));
draw_label(x() + bx, y() + by, w() - bw, h() - bh);
}

View File

@ -23,8 +23,10 @@
#include <FL/Fl_Text_Editor.H>
#include <FL/Fl_Text_Buffer.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Check_Button.H>
#include <edelib/Window.h>
#include <edelib/WindowUtils.h>
#include <edelib/MessageBox.h>
#include <edelib/String.h>
#include <edelib/Regex.h>
@ -41,12 +43,14 @@ EDELIB_NS_USING(String)
EDELIB_NS_USING(Regex)
EDELIB_NS_USING(alert)
EDELIB_NS_USING(message)
EDELIB_NS_USING(window_center_on_screen)
EDELIB_NS_USING(RX_CASELESS)
#ifdef HAVE_CURL
static Fl_Input *bug_title_input;
static Fl_Input *email_input;
static Fl_Text_Buffer *text_buf;
static Fl_Check_Button *notify_reporter;
/* check if string has spaces */
static bool empty_entry(const char *en) {
@ -65,7 +69,7 @@ static bool valid_email(const char *e) {
Regex r;
/* regex stolen from http://www.regular-expressions.info/email.html */
if(!r.compile("\\b[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b", RX_CASELESS)) {
if(!r.compile("^\\b[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b$", RX_CASELESS)) {
E_WARNING(E_STRLOC ": Unable to properly compile regex pattern");
return false;
}
@ -79,8 +83,8 @@ static void close_cb(Fl_Widget*, void *w) {
}
static void send_cb(Fl_Widget*, void *w) {
const char *txt;
String title, content;
const char *txt, *cc = NULL;
String title, content;
if(empty_entry(bug_title_input->value())) {
alert(_("Report title is missing"));
@ -100,7 +104,7 @@ static void send_cb(Fl_Widget*, void *w) {
}
if(!valid_email(email_input->value())) {
alert(_("Email address is invalid. Please use the valid email address"));
alert(_("Email address is invalid. Please use the valid email address so developers can contact you in case more details are needed"));
return;
}
@ -124,7 +128,10 @@ static void send_cb(Fl_Widget*, void *w) {
free((void *) txt);
if(bugzilla_send_with_progress(title.c_str(), content.c_str()))
if(notify_reporter->value())
cc = email_input->value();
if(bugzilla_send_with_progress(title.c_str(), content.c_str(), cc))
close_cb(0, w);
}
#endif /* HAVE_CURL */
@ -156,7 +163,7 @@ int main(int argc, char** argv) {
Fl_Box *description_box = new Fl_Box(80, 45, 390, 95, _("To help us to improve the future EDE versions, "
"please describe the problem with much details as possible.\n\nNote: valid email address is required, so "
"developers could contact you for more informations if necessary."));
"developers can contact you for more informations if necessary."));
description_box->align(133|FL_ALIGN_INSIDE);
@ -182,6 +189,10 @@ int main(int argc, char** argv) {
E_WARNING(E_STRLOC ": Unable to read '%s' as debugger output. Continuing...\n");
}
notify_reporter = new Fl_Check_Button(10, 330, 265, 25, _("Receive notifications"));
notify_reporter->tooltip(_("Receive notifications when developers updates or comments this issue. You have to create EDE Bugzilla account first to get notifications."));
notify_reporter->down_box(FL_DOWN_BOX);
/* resizable box */
Fl_Box *rbox = new Fl_Box(180, 273, 55, 37);
@ -193,8 +204,9 @@ int main(int argc, char** argv) {
Fl_Group::current()->resizable(rbox);
win->window_icon(bug_xpm);
/* win->show(argc, argv); */
win->show();
window_center_on_screen(win);
win->show(argc, argv);
return Fl::run();
#endif /* HAVE_CURL */
}

View File

@ -1,24 +1,24 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0108
version 1.0300
header_name {.h}
code_name {.cxx}
Function {} {open
} {
Fl_Window {} {
label {EDE Bug Reporting Tool} open
xywh {357 193 480 365} type Double resizable visible
xywh {353 189 480 365} type Double resizable visible
} {
Fl_Box {} {
image {../icons/bug.png} xywh {10 10 60 59}
}
Fl_Box {} {
label {EDE Bug Reporting Tool}
xywh {80 10 390 30} labelfont 1 labelsize 14 align 20
xywh {80 10 390 30} labelfont 1 align 20
}
Fl_Box {} {
label {To help us to improve the future EDE versions, please describe the problem with much details as possible.
Note: valid email address is required, so developers could contact you for more informations if necessary.}
Note: valid email address is required, so developers can contact you for more informations if necessary.}
xywh {80 45 390 95} align 149
}
Fl_Input {} {
@ -33,6 +33,10 @@ Note: valid email address is required, so developers could contact you for more
label {Detail description of the problem:}
xywh {10 215 460 105} align 5
}
Fl_Check_Button {} {
label {Receive notifications} selected
tooltip {Receive notifications when developers updates or comments this issue} xywh {10 330 265 25} down_box DOWN_BOX
}
Fl_Button {} {
label {&Send}
xywh {285 330 90 25}
@ -41,8 +45,8 @@ Note: valid email address is required, so developers could contact you for more
label {&Cancel}
xywh {380 330 90 25}
}
Fl_Box {} {selected
xywh {180 273 55 37} labelsize 14 resizable
Fl_Box {} {
xywh {180 273 55 37} resizable
code0 {/* resizable box */}
}
}

View File

@ -86,7 +86,7 @@ void
xmlrpc_set_fault_formatted_v(xmlrpc_env * const envP,
int const code,
const char * const format,
va_list const args) {
va_list args) {
const char * faultDescription;

View File

@ -1,4 +1,6 @@
#define _XOPEN_SOURCE 600 /* Get pselect() in <sys/select.h> */
#if !defined(__SVR4) && !defined(__svr4__)
# define _XOPEN_SOURCE 600 /* Get pselect() in <sys/select.h> */
#endif
#ifdef WIN32
#include <winsock.h>
@ -7,13 +9,14 @@
in others, from <sys/select.h>, and other from both. Including both
in this order appears to work on all.
*/
#include <sys/time.h>
#include <sys/select.h>
#endif
#include <signal.h>
#include "xmlrpc_config.h"
#include "xmlrpc-c/select_int.h"

View File

@ -18,7 +18,7 @@ extern const char * const xmlrpc_strsol;
void
xmlrpc_vasprintf(const char ** const retvalP,
const char * const fmt,
va_list varargs);
va_list varargs);
void GNU_PRINTF_ATTR(2,3)
xmlrpc_asprintf(const char ** const retvalP, const char * const fmt, ...);

View File

@ -140,7 +140,7 @@ void
xmlrpc_set_fault_formatted_v(xmlrpc_env * const envP,
int const code,
const char * const format,
va_list const args);
va_list args);
/* The same as the above, but using a printf-style format string. */
void

View File

@ -29,8 +29,9 @@
/* We hope to replace xmlrpc_amconfig.h some day with something that
doesn't require a whole special set of software to build, to make
Xmlrpc-c approachable by dumber developers.
*/
#include "xmlrpc_amconfig.h"
*/
/* EDE top config file */
#ifdef HAVE_CONFIG_H

View File

@ -14,11 +14,12 @@
#include <config.h>
#endif
#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <FL/Fl.H>
#include <FL/Fl_Box.H>
@ -26,6 +27,7 @@
#include <FL/Fl_Text_Display.H>
#include <FL/Fl_Text_Buffer.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/x.H>
#include <edelib/Nls.h>
#include <edelib/Window.h>
@ -44,6 +46,12 @@
#define WIN_H_NORMAL 130
#define WIN_H_EXPANDED 340
/* two levels of expansion to expand values and then to stringfy them */
#define BUILD_VERSION_STR(maj, min, patch) STRINGFY(maj) "." STRINGFY(min) "." STRINGFY(patch)
#define STRINGFY(s) #s
#define FLTK_VERSION BUILD_VERSION_STR(FL_MAJOR_VERSION, FL_MINOR_VERSION, FL_PATCH_VERSION)
EDELIB_NS_USING(String)
EDELIB_NS_USING(TempFile)
EDELIB_NS_USING(alert)
@ -65,8 +73,7 @@ static void close_cb(Fl_Widget*, void*) {
static void save_as_cb(Fl_Widget*, void*) {
const char *p = fl_file_chooser(_("Save details to..."), "Text Files (*.txt)\tAll Files(*)", "dump.txt");
if(!p)
return;
if(!p) return;
/* so we can have EOL */
txt_buf->append("\n");
@ -77,14 +84,19 @@ static void save_as_cb(Fl_Widget*, void*) {
static void write_host_info(void) {
txt_buf->append("---------- short summary ----------\n");
/* make first X version */
char buf[256];
snprintf(buf, sizeof(buf), "\nX version: %s %i %i.%i", XServerVendor(fl_display), XVendorRelease(fl_display), XProtocolVersion(fl_display), XProtocolRevision(fl_display));
txt_buf->append(buf);
txt_buf->append("\nFLTK version: " FLTK_VERSION);
txt_buf->append("\nEDE version: " PACKAGE_VERSION);
txt_buf->append("\nedelib version: " EDELIB_VERSION);
struct utsname ut;
if(uname(&ut) == 0) {
char buf[1024];
snprintf(buf, sizeof(buf), "%s %s %s %s %s", ut.sysname, ut.nodename, ut.release, ut.version, ut.machine);
txt_buf->append("\nSystem info: ");
txt_buf->append(buf);
}
@ -125,7 +137,11 @@ static void collect_info_once(void) {
TempFile tmp;
tmp.set_auto_delete(true);
if(gdb_output_generate(pdetails->path, tmp))
int pid = -1;
if(pdetails->pid)
pid = atoi(pdetails->pid);
if(gdb_output_generate(pdetails->path, tmp, pid))
txt_buf->appendfile(tmp.name());
info_was_collected = true;
@ -166,7 +182,6 @@ static void report_cb(Fl_Widget*, void*) {
/* close it since we need the file name */
tmp.close();
txt_buf->savefile(tmp.name());
run_async("%s --gdb-dump %s", bug_tool.c_str(), tmp.name());

View File

@ -22,7 +22,6 @@
#include "GdbOutput.h"
/* assume core is placed in current directory */
#define CORE_FILE "core"
EDELIB_NS_USING(String)
@ -37,7 +36,7 @@ static int write_str(int fd, const char *str) {
return ::write(fd, str, len);
}
bool gdb_output_generate(const char *path, TempFile &t) {
bool gdb_output_generate(const char *path, TempFile &t, int pid) {
E_RETURN_VAL_IF_FAIL(path != NULL, false);
int tfd = -1;
@ -71,18 +70,37 @@ bool gdb_output_generate(const char *path, TempFile &t) {
return true;
}
if(!file_test(CORE_FILE, FILE_TEST_IS_REGULAR)) {
write_str(tfd, "Unable to find '"CORE_FILE"'. Backtrace will not be done.");
/*
* to find core file, we will try these strategies: first try to open 'core.PID' if
* we got PID (default on linux); if does not exists, try to open 'core'; everything is
* assumed current folder, whatever it was set
*/
bool core_found = false;
String core_path;
if(pid > -1) {
core_path.printf("%s.%i", CORE_FILE, pid);
if(file_test(core_path.c_str(), FILE_TEST_IS_REGULAR))
core_found = true;
}
if(!core_found) {
core_path = CORE_FILE;
if(file_test(core_path.c_str(), FILE_TEST_IS_REGULAR))
core_found = true;
}
if(!core_found) {
write_str(tfd, "Unable to find core file. Backtrace will not be done.");
/* see it as valid, so dialog could be shown */
return true;
}
pid_t pid = fork();
pid_t gdb_pid = fork();
if(pid == -1) {
if(gdb_pid == -1) {
E_WARNING(E_STRLOC ": Unable to fork the process\n");
return false;
} else if(pid == 0) {
} else if(gdb_pid == 0) {
/* child; redirect to the file */
dup2(tfd, 1);
t.close();
@ -96,7 +114,7 @@ bool gdb_output_generate(const char *path, TempFile &t) {
argv[3] = (char*)"-x";
argv[4] = (char*)scr.name();
argv[5] = (char*)path;
argv[6] = (char*)CORE_FILE;
argv[6] = (char*)core_path.c_str();
argv[7] = 0;
execvp(argv[0], argv);
@ -104,12 +122,12 @@ bool gdb_output_generate(const char *path, TempFile &t) {
} else {
int status;
if(waitpid(pid, &status, 0) != pid) {
if(waitpid(gdb_pid, &status, 0) != gdb_pid) {
E_WARNING(E_STRLOC ": Failed to execute waitpid() properly\n");
return false;
}
}
file_remove(CORE_FILE);
file_remove(core_path.c_str());
return true;
}

View File

@ -13,6 +13,6 @@
#ifndef __GDBOUTPUT_H__
#define __GDBOUTPUT_H__
bool gdb_output_generate(const char *path, edelib::TempFile &t);
bool gdb_output_generate(const char *path, edelib::TempFile &t, int pid = -1);
#endif

View File

@ -3,7 +3,7 @@
*
* Desktop configuration tool
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2007-2008 EDE Authors.
* Copyright (c) 2007-2014 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
@ -29,7 +29,6 @@
#include <FL/Fl_Color_Chooser.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_Tiled_Image.H>
#include <FL/Fl_Menu_Button.H>
#include <FL/x.H>
@ -43,6 +42,9 @@
#include <edelib/Directory.h>
#include <edelib/ForeignCallback.h>
#include <edelib/Ede.h>
#include <edelib/Netwm.h>
EDELIB_NS_USING(netwm_workarea_get_size)
#define EDE_DESKTOP_CONFIG "ede-desktop"
@ -53,7 +55,7 @@ Fl_Menu_Item mode_menu[] = {
{0}
};
// make sure this part matches array positions in mode_menu[]
/* make sure this part matches array positions in mode_menu[] */
#define IMG_CENTER 0
#define IMG_STRETCH 1
#define IMG_TILE 2
@ -79,7 +81,79 @@ Fl_Input* icon_font_txt;
Fl_Check_Button* engage_with_one_click;
void set_wallpaper(const char* path) {
#define PIXEL_POS(x, y, w, d) ((((y) * (w)) + (x)) * (d))
/* TODO: the same function exists in ede-desktop: move this to edelib */
static Fl_RGB_Image* create_tile(Fl_Image *orig, int X, int Y, int W, int H) {
/* don't tile large image */
if(orig->w() >= W && orig->h() >= H)
return (Fl_RGB_Image*)orig;
int iw = orig->w();
int ih = orig->h();
int idepth = orig->d();
int tx = X - (X % iw);
int ty = Y - (Y % ih);
int tw = W + tx;
int th = H + ty;
unsigned char* dest = new unsigned char[tw * th * orig->d()];
unsigned char* destptr = dest;
unsigned char* src = (unsigned char*)orig->data()[0];
int ppos = 0;
/* for bounds checks */
int imax = iw * ih * idepth;
if(idepth == 3 || idepth == 4) {
for(int j = 0, cj = 0; j < th; j++, cj++) {
if(cj > ih) cj = 0;
for(int i = 0, ci = 0; i < tw; i++, ci++) {
if(ci > iw) ci = 0;
ppos = PIXEL_POS(ci, cj, iw, idepth);
if(ppos > imax) ppos = imax;
*destptr++ = src[ppos];
*destptr++ = src[ppos + 1];
*destptr++ = src[ppos + 2];
if(idepth == 4)
*destptr++ = src[ppos + 3];
}
}
} else if(idepth == 2) {
for(int j = 0, cj = 0; j < th; j++, cj++) {
if(cj > ih) cj = 0;
for(int i = 0, ci = 0; i < tw; i++, ci++) {
if(ci > iw) ci = 0;
ppos = PIXEL_POS(ci, cj, iw, idepth);
if(ppos > imax) ppos = imax;
*destptr++ = src[ppos];
*destptr++ = src[ppos + 1];
}
}
} else {
for(int j = 0, cj = 0; j < th; j++, cj++) {
if(cj > ih) cj = 0;
for(int i = 0, ci = 0; i < tw; i++, ci++) {
if(ci > iw) ci = 0;
ppos = PIXEL_POS(ci, cj, iw, idepth);
if(ppos > imax) ppos = imax;
*destptr++ = src[ppos];
}
}
}
Fl_RGB_Image* c = new Fl_RGB_Image(dest, tw, th, idepth, orig->ld());
c->alloc_array = 1;
return c;
}
static void set_wallpaper(const char* path) {
if(!path)
return;
@ -101,19 +175,12 @@ void set_wallpaper(const char* path) {
* Before doing anything with the image, first scale it relative to wallpaper box,
* which is relative to the screen sizes.
*/
int display_w = DisplayWidth(fl_display, fl_screen);
int display_h = DisplayHeight(fl_display, fl_screen);
int scale_w_factor, scale_h_factor;
int X, Y, W, H;
if(!netwm_workarea_get_size(X, Y, W, H))
Fl::screen_xywh(X, Y, W, H);
if(display_w > area_w)
scale_w_factor = display_w / area_w;
else
scale_w_factor = 1;
if(display_h > area_h)
scale_h_factor = display_h / area_h;
else
scale_h_factor = 1;
int scale_w_factor = (W > area_w) ? W / area_w : 1;
int scale_h_factor = (H > area_h) ? H / area_h : 1;
Fl_Image* rel_img = img->copy(img->w() / scale_w_factor, img->h() / scale_h_factor);
@ -134,9 +201,8 @@ void set_wallpaper(const char* path) {
}
case IMG_TILE: {
Fl_Tiled_Image* tiled = new Fl_Tiled_Image(rel_img, area_w, area_h);
wallpaper_img->size(area_w, area_h);
wallpaper_img->image(tiled);
wallpaper_img->image(create_tile(rel_img, 0, 0, area_w, area_h));
break;
}
@ -168,7 +234,7 @@ void set_wallpaper(const char* path) {
}
}
void disable_wallpaper(bool doit) {
static void disable_wallpaper(bool doit) {
if(doit) {
desk_use_wallpaper->value(0);
desk_background_mode->deactivate();
@ -191,17 +257,12 @@ void disable_wallpaper(bool doit) {
wallpaper->redraw();
}
void set_rgb_color(Fl_Button* btn, unsigned char r, unsigned char g, unsigned char b) {
Fl_Color c = (Fl_Color)edelib::color_rgb_to_fltk(r, g, b);
btn->color(c);
}
void close_cb(Fl_Widget*, void* w) {
static void close_cb(Fl_Widget*, void* w) {
edelib::Window* win = (edelib::Window*)w;
win->hide();
}
void color_cb(Fl_Widget* btn, void*) {
static void color_cb(Fl_Widget* btn, void*) {
unsigned char r, g, b;
edelib::color_fltk_to_rgb(btn->color(), r, g, b);
@ -212,7 +273,7 @@ void color_cb(Fl_Widget* btn, void*) {
}
}
void wallpaper_color_cb(Fl_Widget*, void* w) {
static void wallpaper_color_cb(Fl_Widget*, void* w) {
unsigned char r, g, b;
edelib::color_fltk_to_rgb(desk_background_color->color(), r, g, b);
@ -227,7 +288,7 @@ void wallpaper_color_cb(Fl_Widget*, void* w) {
}
}
void browse_cb(Fl_Widget*, void*) {
static void browse_cb(Fl_Widget*, void*) {
char* ret = fl_file_chooser(_("Background image"), "*.jpg\t*.png", desk_background->value());
if(!ret)
return;
@ -237,7 +298,7 @@ void browse_cb(Fl_Widget*, void*) {
wallpaper->redraw();
}
void wallpaper_use_cb(Fl_Widget*, void*) {
static void wallpaper_use_cb(Fl_Widget*, void*) {
if(desk_use_wallpaper->value()) {
disable_wallpaper(false);
set_wallpaper(desk_background->value());
@ -245,13 +306,13 @@ void wallpaper_use_cb(Fl_Widget*, void*) {
disable_wallpaper(true);
}
void choice_cb(Fl_Widget*, void*) {
static void choice_cb(Fl_Widget*, void*) {
set_wallpaper(desk_background->value());
wallpaper_img->redraw();
wallpaper->redraw();
}
void apply_cb(Fl_Widget*, void* w) {
static void apply_cb(Fl_Widget*, void* w) {
edelib::Resource conf;
conf.set("Desktop", "color", (int)desk_background_color->color());
conf.set("Desktop", "wallpaper_use", desk_use_wallpaper->value());
@ -273,7 +334,7 @@ void apply_cb(Fl_Widget*, void* w) {
edelib::foreign_callback_call("ede-desktop");
}
void ok_cb(Fl_Widget*, void* w) {
static void ok_cb(Fl_Widget*, void* w) {
edelib::Window* win = (edelib::Window*)w;
apply_cb(0, win);
/* a hack so ede-desktop-conf can send a message before it was closed */
@ -281,7 +342,7 @@ void ok_cb(Fl_Widget*, void* w) {
win->hide();
}
void browse_fonts_cb(Fl_Widget*, void* w) {
static void browse_fonts_cb(Fl_Widget*, void* w) {
Fl_Input* in = (Fl_Input*)w;
int retsz;
const char* font_name = Fl::get_font_name((Fl_Font)icon_font, 0);
@ -296,7 +357,7 @@ void browse_fonts_cb(Fl_Widget*, void* w) {
icon_font_size = retsz;
}
void load_settings(void) {
static void load_settings(void) {
int b_mode = 0;
bool d_wp_use = false;
int d_background_color = fl_rgb_color(73, 64, 102); /* keep it in sync with default color in ede-desktop */
@ -376,13 +437,11 @@ int main(int argc, char** argv) {
g1->hide();
g1->begin();
/*
Fl_Box* b1 = new Fl_Box(85, 196, 100, 15);
b1->box(FL_BORDER_BOX);
b1->box(FL_THIN_UP_BOX);
Fl_Box* b2 = new Fl_Box(30, 43, 210, 158);
b2->box(FL_THIN_UP_BOX);
*/
/* box size is intentionaly odd so preserve aspect ratio */
wallpaper = new Fl_Box(43, 53, 184, 138);

871
ede-desktop/Desktop.cpp Normal file
View File

@ -0,0 +1,871 @@
/*
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
#include <dirent.h>
#include <limits.h>
#include <stdlib.h>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <edelib/Debug.h>
#include <edelib/Netwm.h>
#include <edelib/WindowUtils.h>
#include <edelib/ForeignCallback.h>
#include <edelib/MenuItem.h>
#include <edelib/Nls.h>
#include <edelib/StrUtil.h>
#include <edelib/Directory.h>
#include <edelib/Util.h>
#include <edelib/Run.h>
#include <edelib/MessageBox.h>
#include <edelib/IconLoader.h>
#include <edelib/FontCache.h>
#include <edelib/FileTest.h>
#include <edelib/File.h>
#include "Desktop.h"
#include "DesktopIcon.h"
#include "Wallpaper.h"
#include "Utils.h"
#include "IconDialog.h"
EDELIB_NS_USING(MenuButton)
EDELIB_NS_USING(MenuItem)
EDELIB_NS_USING(String)
EDELIB_NS_USING(DesktopFile)
EDELIB_NS_USING(IconLoader)
EDELIB_NS_USING(window_xid_create)
EDELIB_NS_USING(netwm_window_set_type)
EDELIB_NS_USING(netwm_workarea_get_size)
EDELIB_NS_USING(netwm_callback_add)
EDELIB_NS_USING(foreign_callback_add)
EDELIB_NS_USING(str_ends)
EDELIB_NS_USING(dir_home)
EDELIB_NS_USING(dir_empty)
EDELIB_NS_USING(dir_remove)
EDELIB_NS_USING(build_filename)
EDELIB_NS_USING(run_async)
EDELIB_NS_USING(input)
EDELIB_NS_USING(alert)
EDELIB_NS_USING(dir_create)
EDELIB_NS_USING(file_test)
EDELIB_NS_USING(file_remove)
EDELIB_NS_USING(font_cache_find)
EDELIB_NS_USING(FILE_TEST_IS_DIR)
EDELIB_NS_USING(FILE_TEST_IS_REGULAR)
EDELIB_NS_USING(FILE_TEST_IS_SYMLINK)
EDELIB_NS_USING(NETWM_WINDOW_TYPE_DESKTOP)
EDELIB_NS_USING(NETWM_CHANGED_CURRENT_WORKAREA)
EDELIB_NS_USING(DESK_FILE_TYPE_UNKNOWN)
EDELIB_NS_USING(ICON_SIZE_TINY)
#define DOT_OR_DOTDOT(base) (base[0] == '.' && (base[1] == '\0' || (base[1] == '.' && base[2] == '\0')))
#define NOT_SELECTABLE(widget) ((widget == this) || (widget == wallpaper) || (widget == dmenu))
#define SELECTION_SINGLE (Fl::event_button() == 1)
#define SELECTION_MULTI (Fl::event_button() == 1 && (Fl::event_key(FL_Shift_L) || Fl::event_key(FL_Shift_R)))
#undef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#undef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define ICONS_POS_FILE "ede-desktop-icons"
static void background_conf_cb(Fl_Widget*, void*);
static void icons_conf_cb(Fl_Widget*, void*);
static void folder_create_cb(Fl_Widget*, void*);
static void launcher_create_cb(Fl_Widget*, void*);
static void arrange_icons_cb(Fl_Widget*, void*);
struct SelectionOverlay {
int x, y, w, h;
bool show;
SelectionOverlay() : x(0), y(0), w(0), h(0), show(false) { }
};
static MenuItem desktop_menu[] = {
{_("Create &launcher..."), 0, launcher_create_cb},
{_("Create &folder..."), 0, folder_create_cb, 0, FL_MENU_DIVIDER},
{_("A&rrange icons"), 0, arrange_icons_cb, 0, FL_MENU_DIVIDER},
{_("&Icons settings..."), 0, icons_conf_cb, 0},
{_("&Background..."), 0, background_conf_cb, 0},
{0}
};
inline bool intersects(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) {
return (MAX(x1, x2) <= MIN(w1, w2) &&
MAX(y1, y2) <= MIN(h1, h2));
}
static void make_me_desktop(Fl_Window *win) {
netwm_window_set_type(fl_xid(win), NETWM_WINDOW_TYPE_DESKTOP);
}
static void settings_changed_cb(Fl_Window *win, void *data) {
Desktop *d = (Desktop*)win;
d->read_config();
}
static void desktop_message_handler(int action, Window xid, void *data) {
Desktop *d = (Desktop*)data;
switch(action) {
case NETWM_CHANGED_CURRENT_WORKAREA:
d->update_workarea();
break;
}
}
static void background_conf_cb(Fl_Widget*, void*) {
run_async("ede-launch ede-desktop-conf");
}
static void icons_conf_cb(Fl_Widget*, void*) {
run_async("ede-launch ede-desktop-conf --icons");
}
static void launcher_create_cb(Fl_Widget*, void* d) {
Desktop *self = (Desktop*)d;
icon_dialog_icon_create(self);
}
static void arrange_icons_cb(Fl_Widget*, void *d) {
E_RETURN_IF_FAIL(d != NULL);
Desktop *self = (Desktop*)d;
self->arrange_icons();
self->redraw();
}
static void folder_create_cb(Fl_Widget*, void *d) {
E_RETURN_IF_FAIL(d != NULL);
const char *n = input(_("Create a new folder with the name"));
if(!n) return;
Desktop *self = (Desktop*)d;
self->create_folder(n);
}
Desktop::Desktop() : EDE_DESKTOP_WINDOW(0, 0, 100, 100, EDE_DESKTOP_APP) {
end();
/* use nice darker blue color as default for background */
color(fl_rgb_color(73, 64, 102));
conf = NULL;
selbox = new SelectionOverlay;
icon_opts = NULL;
wallpaper = NULL;
dmenu = NULL;
selection_x = selection_y = 0;
last_px = last_py = -1;
moving = false;
/*
* first update workarea _then_ read configuration, as it will have correct size for
* wallpaper which will prevent wallpaper load and scalle image twice
*/
update_workarea();
read_config();
read_desktop_folder(desktop_path());
foreign_callback_add(this, EDE_DESKTOP_APP, settings_changed_cb);
dmenu = new MenuButton(0, 0, 500, 0);
dmenu->menu(desktop_menu);
desktop_menu[1].image((Fl_Image*)IconLoader::get("folder", ICON_SIZE_TINY));
desktop_menu[0].user_data(this);
desktop_menu[1].user_data(this);
desktop_menu[2].user_data(this);
add(dmenu);
}
Desktop::~Desktop() {
E_DEBUG("Desktop::~Desktop()\n");
delete conf;
delete icon_opts;
delete selbox;
}
const char *Desktop::desktop_path(void) {
if(dpath.empty())
dpath = build_filename(dir_home().c_str(), "Desktop");
return dpath.c_str();
}
void Desktop::show(void) {
if(shown()) {
EDE_DESKTOP_WINDOW::show();
return;
}
window_xid_create(this, make_me_desktop);
netwm_callback_add(desktop_message_handler, this);
}
void Desktop::update_workarea(void) {
int X, Y, W, H;
if(!netwm_workarea_get_size(X, Y, W, H))
Fl::screen_xywh(X, Y, W, H);
update_workarea(X, Y, W, H);
}
void Desktop::update_workarea(int X, int Y, int W, int H) {
/* prevent multiple calls with the same values */
if(X == x() && Y == y() && W == w() && H == h())
return;
E_DEBUG(E_STRLOC ": resizing to %i %i %i %i (was: %i %i %i %i)\n",
X, Y, W, H, x(), y(), w(), h());
/*
* Check if wallpaper needs resizing. Sometimes, while screen size is updated
* X11 can change x/y, but keep w/h; here, wallpaper size update is not needed.
*/
bool resize_wallpaper = !(W == w() && H == h());
resize(X, Y, W, H);
/* also resize wallpaper if given */
if(wallpaper && wallpaper->visible() && resize_wallpaper) {
E_DEBUG(E_STRLOC ": resizing wallpaper to %i %i\n", W, H);
wallpaper->resize(0, 0, W, H);
}
}
void Desktop::read_config(void) {
E_DEBUG(E_STRLOC ": Reading desktop config...\n");
if(!conf) conf = new DesktopConfig();
conf->load(EDE_DESKTOP_APP);
char buf[PATH_MAX];
bool wp_use = true;
int bcolor;
if(conf->get("Desktop", "color", bcolor, color()))
color(bcolor);
conf->get("Desktop", "wallpaper_use", wp_use, wp_use);
/* get wallpaper */
if(wp_use) {
if(conf->get("Desktop", "wallpaper", buf, sizeof(buf))) {
if(!wallpaper)
wallpaper = new Wallpaper(0, 0, w(), h());
int s;
bool rootpmap_use;
conf->get("Desktop", "wallpaper_mode", s, WALLPAPER_CENTER);
conf->get("Desktop", "wallpaper_rootpmap", rootpmap_use, true);
wallpaper->load(buf, s, rootpmap_use);
/*
* wallpaper is another widget, but we add it to the bottom of the list
* to preserve stacking order
*/
if(find(*wallpaper) == children())
insert(*wallpaper, 0);
/* show it in case it got hidden before */
wallpaper->show();
}
} else {
if(wallpaper) wallpaper->hide();
}
if(!icon_opts) icon_opts = new IconOptions;
#define ICON_CONF_GET(var) conf->get("Icons", #var, icon_opts->var, icon_opts->var)
ICON_CONF_GET(label_background);
ICON_CONF_GET(label_foreground);
ICON_CONF_GET(label_maxwidth);
ICON_CONF_GET(label_transparent);
ICON_CONF_GET(label_visible);
ICON_CONF_GET(one_click_exec);
if(ICON_CONF_GET(label_font) && ICON_CONF_GET(label_fontsize))
E_WARNING(E_STRLOC ": 'label_font' && 'label_fontsize' are deprecated. Use 'label_fontname' with full font name and size instead (e.g 'sans 12')\n");
/* if found new 'label_fontname' variable, overwrite 'label_font' && 'label_fontsize' */
if(conf->get("Icons", "label_fontname", buf, sizeof(buf))) {
if(!font_cache_find(buf, (Fl_Font&)icon_opts->label_font, icon_opts->label_fontsize))
E_WARNING(E_STRLOC ": Unable to find '%s' font. Using default values...\n", buf);
}
icon_opts->sanitize_font();
/* doing this will redraw _all_ children, and they will in turn read modified 'icon_opts' */
if(visible()) redraw();
}
void Desktop::read_desktop_folder(const char *dpath) {
E_RETURN_IF_FAIL(dpath != NULL);
String path;
DIR *dir = opendir(dpath);
E_RETURN_IF_FAIL(dir != NULL);
DesktopConfig pos;
pos.load(ICONS_POS_FILE);
dirent *d;
while((d = readdir(dir)) != NULL) {
if(DOT_OR_DOTDOT(d->d_name))
continue;
if(d->d_type > 0) {
if(d->d_type != DT_REG && d->d_type != DT_LNK && d->d_type != DT_DIR)
continue;
path = dpath;
path += E_DIR_SEPARATOR;
path += d->d_name;
} else {
/*
* If we got here, it means d_type isn't set and we must do it via file_test() which could be much slower.
* By POSIX standard, only d_name must be set, but many modern *nixes set all dirent members correctly. Except Slackware ;)
*/
path = dpath;
path += E_DIR_SEPARATOR;
path += d->d_name;
if(!(file_test(path.c_str(), FILE_TEST_IS_REGULAR) ||
file_test(path.c_str(), FILE_TEST_IS_DIR) ||
file_test(path.c_str(), FILE_TEST_IS_SYMLINK)))
continue;
}
DesktopIcon *o = read_desktop_file(path.c_str(), (const char*)d->d_name, &pos);
if(o) add(o);
}
closedir(dir);
}
DesktopIcon *Desktop::read_desktop_file(const char *path, const char *base, DesktopConfig *pos) {
DesktopIcon *ret = NULL;
if(file_test(path, FILE_TEST_IS_DIR)) {
ret = new DesktopIcon(_("No Name"));
ret->set_icon_type(DESKTOP_ICON_TYPE_FOLDER);
/* hardcoded */
ret->set_image("folder");
/* copy label explicitly, as DesktopIcon() will only store a pointer */
ret->copy_label(base);
} else {
/*
* try to load it as plain .desktop file by looking only at extension
* TODO: MimeType can be used here too
*/
if(!str_ends(path, EDE_DESKTOP_DESKTOP_EXT))
return ret;
DesktopFile df;
char buf[PATH_MAX];
E_RETURN_VAL_IF_FAIL(df.load(path), ret);
E_RETURN_VAL_IF_FAIL(df.type() != DESK_FILE_TYPE_UNKNOWN, ret);
ret = new DesktopIcon(_("No Name"));
ret->set_icon_type(DESKTOP_ICON_TYPE_NORMAL);
if(df.name(buf, sizeof(buf))) ret->copy_label(buf);
ret->set_image(df.icon(buf, sizeof(buf)) ? buf : NULL);
if(df.comment(buf, sizeof(buf))) ret->set_tooltip(buf);
}
/* try to put random icon position in the middle of the desktop, so it is easier to notice */
int X = (rand() % (w() / 4)) + (w() / 4);
int Y = (rand() % (h() / 4)) + (h() / 4);
/* lookup icons locations if possible */
if(base && pos && *pos) {
pos->get(base, "X", X, X);
pos->get(base, "Y", Y, Y);
}
E_DEBUG("Setting icon '%s' (%i,%i)\n", base, X, Y);
ret->position(X, Y);
/* use loaded icon options */
ret->set_options(icon_opts);
ret->set_path(path);
return ret;
}
void Desktop::arrange_icons(void) {
int lw = icon_opts ? icon_opts->label_maxwidth : 75;
int X = (lw / 5) + 10;
int Y = 10;
int H = h();
DesktopIcon *o;
for(int i = 0; i < children(); i++) {
if(NOT_SELECTABLE(child(i))) continue;
o = (DesktopIcon*)child(i);
o->position(X, Y);
Y += o->h() + (o->h() / 2);
if(Y + (o->h() / 2) > H) {
Y = 10;
X += lw + (o->w() / 2);
}
}
}
bool Desktop::remove_icon(DesktopIcon *di, bool real_delete) {
bool ret = true;
if(real_delete) {
if(di->get_icon_type() == DESKTOP_ICON_TYPE_FOLDER) {
if(!dir_empty(di->get_path())) {
alert(_("This folder is not empty. Recursive removal of not empty folders is not yet supported"));
return false;
}
ret = dir_remove(di->get_path());
} else {
ret = file_remove(di->get_path());
}
}
remove(di);
redraw();
return ret;
}
bool Desktop::rename_icon(DesktopIcon *di, const char *name) {
di->copy_label(name);
di->update_label_font_and_size();
di->fast_redraw();
/* open file and try to change the name */
DesktopFile df;
E_RETURN_VAL_IF_FAIL(df.load(di->get_path()) == true, false);
df.set_name(name);
return df.save(di->get_path());
}
void Desktop::edit_icon(DesktopIcon *di) {
icon_dialog_icon_edit(this, di);
}
bool Desktop::save_icons_positions(void) {
DesktopConfig pos;
DesktopIcon *o;
char *base;
for(int i = 0; i < children(); i++) {
if(NOT_SELECTABLE(child(i))) continue;
o = (DesktopIcon*)child(i);
base = get_basename(o->get_path());
pos.set(base, "X", o->x());
pos.set(base, "Y", o->y());
}
return pos.save(ICONS_POS_FILE);
}
bool Desktop::create_folder(const char *name) {
String path = desktop_path();
path += E_DIR_SEPARATOR;
path += name;
if(!dir_create(path.c_str())) {
alert(_("Unable to create directory '%s'! Please check if directory already exists or you have enough permissions to create it"), path.c_str());
return false;
}
DesktopIcon *ic = read_desktop_file(path.c_str(), name);
if(ic) {
/* use mouse position so folder icon gets created where was clicked */
ic->position(last_px, last_py);
add(ic);
redraw();
}
return true;
}
void Desktop::unfocus_all(void) {
DesktopIcon *o;
for(int i = 0; i < children(); i++) {
if(NOT_SELECTABLE(child(i))) continue;
o = (DesktopIcon*)child(i);
o->do_unfocus();
o->fast_redraw();
}
}
void Desktop::select(DesktopIcon *ic, bool do_redraw) {
E_ASSERT(ic != NULL);
if(in_selection(ic)) return;
selectionbuf.push_back(ic);
if(!ic->is_focused()) {
ic->do_focus();
if(do_redraw) ic->fast_redraw();
}
}
void Desktop::select_only(DesktopIcon *ic) {
E_ASSERT(ic != NULL);
unfocus_all();
selectionbuf.clear();
selectionbuf.push_back(ic);
ic->do_focus();
ic->fast_redraw();
}
bool Desktop::in_selection(const DesktopIcon* ic) {
E_ASSERT(ic != NULL);
if(selectionbuf.empty())
return false;
for(DesktopIconListIt it = selectionbuf.begin(), ite = selectionbuf.end(); it != ite; ++it) {
if((*it) == ic)
return true;
}
return false;
}
void Desktop::move_selection(int x, int y, bool apply) {
if(selectionbuf.empty()) return;
int prev_x, prev_y, tmp_x, tmp_y;
DesktopIcon *ic;
for(DesktopIconListIt it = selectionbuf.begin(), ite = selectionbuf.end(); it != ite; ++it) {
ic = (*it);
prev_x = ic->drag_icon_x();
prev_y = ic->drag_icon_y();
tmp_x = x - selection_x;
tmp_y = y - selection_y;
ic->drag(prev_x + tmp_x, prev_y + tmp_y, apply);
}
selection_x = x;
selection_y = y;
/*
* move the last moved icon on the top of the stack, so it be drawn the top most; also
* when called arrange_icons(), last moved icon will be placed last in the list
*/
ic = selectionbuf.back();
insert(*ic, children());
if(apply) {
redraw();
save_icons_positions();
}
}
/*
* Tries to figure out icon below mouse. It is alternative to Fl::belowmouse() since with this we hunt
* only icons, not other childs (wallpaper, menu), which can be returned by Fl::belowmouse() and bad
* things be hapened.
*/
DesktopIcon* Desktop::below_mouse(int px, int py) {
DesktopIcon *o;
for(int i = 0; i < children(); i++) {
if(NOT_SELECTABLE(child(i))) continue;
o = (DesktopIcon*)child(i);
if(o->x() < px && o->y() < py && px < (o->x() + o->h()) && py < (o->y() + o->h()))
return o;
}
return NULL;
}
void Desktop::select_in_area(void) {
if(!selbox->show) return;
int ax = selbox->x;
int ay = selbox->y;
int aw = selbox->w;
int ah = selbox->h;
if(aw < 0) {
ax += aw;
aw = -aw;
} else if(!aw)
aw = 1;
if(ah < 0) {
ay += ah;
ah = -ah;
} else if(!ah)
ah = 1;
/*
* XXX: This function can fail since icon coordinates are absolute (event_x_root)
* but selbox use relative (event_root). It will work as expected if desktop is at x=0 y=0.
* This should be checked further.
*/
DesktopIcon* o;
for(int i = 0; i < children(); i++) {
if(NOT_SELECTABLE(child(i))) continue;
o = (DesktopIcon*)child(i);
if(intersects(ax, ay, ax+aw, ay+ah, o->x(), o->y(), o->w()+o->x(), o->h()+o->y())) {
if(!o->is_focused()) {
o->do_focus();
/* updated from Desktop::draw() */
o->damage(EDE_DESKTOP_DAMAGE_CHILD_LABEL);
}
} else {
if(o->is_focused()) {
o->do_unfocus();
o->fast_redraw();
}
}
}
}
void Desktop::draw(void) {
if(!damage()) return;
if(damage() & (FL_DAMAGE_ALL | FL_DAMAGE_EXPOSE)) {
/*
* If any overlay was previously visible during full redraw, it will not be cleared because of fast flip.
* This will assure that does not happened.
*/
fl_overlay_clear();
EDE_DESKTOP_WINDOW::draw();
//E_DEBUG(E_STRLOC ": REDRAW ALL\n");
}
if(damage() & EDE_DESKTOP_DAMAGE_OVERLAY) {
if(selbox->show)
fl_overlay_rect(selbox->x, selbox->y, selbox->w, selbox->h);
else
fl_overlay_clear();
/*
* now scan all icons and see if they needs redraw, and if do
* just update their label since it is indicator of selection
*/
for(int i = 0; i < children(); i++) {
if(child(i)->damage() == EDE_DESKTOP_DAMAGE_CHILD_LABEL) {
update_child(*child(i));
child(i)->clear_damage();
//E_DEBUG(E_STRLOC ": ICON REDRAW \n");
}
}
}
clear_damage();
}
int Desktop::handle(int event) {
switch(event) {
case FL_FOCUS:
case FL_UNFOCUS:
case FL_SHORTCUT:
return 1;
case FL_PUSH: {
/*
* First check where we clicked. If we do it on desktop unfocus any possible focused childs, and handle
* specific clicks. Otherwise, do rest for childs.
*/
Fl_Widget* clicked = Fl::belowmouse();
if(NOT_SELECTABLE(clicked)) {
//E_DEBUG(E_STRLOC ": DESKTOP CLICK !!!\n");
if(!selectionbuf.empty()) {
/*
* Only focused are in selectionbuf, so this is fine to do; also will prevent
* full redraw when is clicked on desktop
*/
unfocus_all();
selectionbuf.clear();
}
/* track position so moving can be deduced */
if(Fl::event_button() == 1) {
selbox->x = Fl::event_x();
selbox->y = Fl::event_y();
} else if(Fl::event_button() == 3) {
last_px = Fl::event_x();
last_py = Fl::event_y();
damage(EDE_DESKTOP_DAMAGE_OVERLAY);
const edelib::MenuItem* item = dmenu->menu()->popup(Fl::event_x(), Fl::event_y());
dmenu->picked(item);
}
return 1;
}
/* from here, all events are managed for icons */
DesktopIcon* tmp_icon = (DesktopIcon*)clicked;
/* do no use assertion on this, since fltk::belowmouse() can miss our icon */
if(!tmp_icon) return 1;
if(SELECTION_MULTI) {
Fl::event_is_click(0);
select(tmp_icon);
return 1;
} else if(SELECTION_SINGLE) {
if(!in_selection(tmp_icon)) {
select_only(tmp_icon);
}
} else if(Fl::event_button() == 3) {
select_only(tmp_icon);
}
/*
* Let child handle the rest.
* Also prevent click on other mouse buttons during move.
*/
if(!moving)
tmp_icon->handle(FL_PUSH);
//E_DEBUG(E_STRLOC ": FL_PUSH from desktop\n");
selection_x = Fl::event_x_root();
selection_y = Fl::event_y_root();
return 1;
}
case FL_DRAG:
moving = true;
if(!selectionbuf.empty()) {
//E_DEBUG(E_STRLOC ": DRAG icon from desktop\n");
move_selection(Fl::event_x_root(), Fl::event_y_root(), false);
} else {
//E_DEBUG(E_STRLOC ": DRAG from desktop\n");
/*
* Moving is started with pushed button.
* From this point selection box is created and is rolled until release
*/
if(selbox->x != 0 || selbox->y != 0) {
selbox->w = Fl::event_x() - selbox->x;
selbox->h = Fl::event_y() - selbox->y;
selbox->show = true;
/* see if there some icons inside selection area */
select_in_area();
/* redraw selection box */
damage(EDE_DESKTOP_DAMAGE_OVERLAY);
}
}
return 1;
case FL_RELEASE:
//E_DEBUG(E_STRLOC ": RELEASE from desktop\n");
//E_DEBUG(E_STRLOC ": clicks: %i\n", Fl::event_is_click());
if(selbox->show) {
selbox->x = selbox->y = selbox->w = selbox->h = 0;
selbox->show = false;
damage(EDE_DESKTOP_DAMAGE_OVERLAY);
/*
* Now pickup those who are in is_focused() state.
*
* Possible flickers due overlay will be later removed when is called move_selection(), which
* will in turn redraw icons again after position them.
*/
if(!selectionbuf.empty())
selectionbuf.clear();
DesktopIcon *o;
for(int i = 0; i < children(); i++) {
if(NOT_SELECTABLE(child(i))) continue;
o = (DesktopIcon*)child(i);
if(o->is_focused())
select(o, false);
}
return 1;
}
if(!selectionbuf.empty() && moving)
move_selection(Fl::event_x_root(), Fl::event_y_root(), true);
/*
* Do not send FL_RELEASE during move
* TODO: should be alowed FL_RELEASE to multiple icons? (aka. run command for all selected icons)?
*/
if(selectionbuf.size() == 1 && !moving)
selectionbuf.front()->handle(FL_RELEASE);
moving = false;
return 1;
case FL_DND_ENTER:
case FL_DND_DRAG:
case FL_DND_LEAVE:
return 1;
case FL_DND_RELEASE: {
DesktopIcon* di = below_mouse(Fl::event_x(), Fl::event_y());
if(di) return di->handle(event);
return 1;
}
case FL_PASTE: {
DesktopIcon* di = below_mouse(Fl::event_x(), Fl::event_y());
if(di) return di->handle(event);
return 1;
}
case FL_ENTER:
case FL_LEAVE:
case FL_MOVE:
return EDE_DESKTOP_WINDOW::handle(event);
default:
break;
}
return 0;
}

101
ede-desktop/Desktop.h Normal file
View File

@ -0,0 +1,101 @@
/*
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* Copyright (C) 2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __EDE_DESKTOP_H__
#define __EDE_DESKTOP_H__
#include <edelib/MenuButton.h>
#include <edelib/DesktopFile.h>
#include <edelib/Config.h>
#include <edelib/List.h>
#include <edelib/String.h>
#ifdef USE_EDELIB_WINDOW
# include <edelib/Window.h>
# define EDE_DESKTOP_WINDOW EDELIB_NS_PREPEND(Window)
#else
# include <FL/Fl_Window.H>
# define EDE_DESKTOP_WINDOW Fl_Window
#endif
#include "Globals.h"
#define EDE_DESKTOP_APP "ede-desktop"
struct SelectionOverlay;
struct IconOptions;
class DesktopIcon;
class Wallpaper;
typedef EDELIB_NS_PREPEND(list)<DesktopIcon*> DesktopIconList;
typedef EDELIB_NS_PREPEND(list)<DesktopIcon*>::iterator DesktopIconListIt;
class Desktop : public EDE_DESKTOP_WINDOW {
private:
SelectionOverlay *selbox;
DesktopConfig *conf;
IconOptions *icon_opts;
EDELIB_NS_PREPEND(String) dpath;
EDELIB_NS_PREPEND(MenuButton) *dmenu;
Wallpaper *wallpaper;
int selection_x, selection_y;
/* last recorded pointer position, so icon can be created at position where menu is clicked */
int last_px, last_py;
bool moving;
/* so we can track selected icons; one or multiselection */
DesktopIconList selectionbuf;
public:
Desktop();
~Desktop();
const char *desktop_path(void);
void show(void);
void update_workarea(void);
void update_workarea(int X, int Y, int W, int H);
void read_config(void);
void read_desktop_folder(const char *dpath = NULL);
DesktopIcon *read_desktop_file(const char *path, const char *base = 0, DesktopConfig *positions = 0);
void arrange_icons(void);
bool remove_icon(DesktopIcon *di, bool real_delete);
bool rename_icon(DesktopIcon *di, const char *name);
void edit_icon(DesktopIcon *di);
bool save_icons_positions(void);
bool create_folder(const char *name);
void unfocus_all(void);
void select(DesktopIcon *ic, bool do_redraw = true);
void select_only(DesktopIcon *ic);
bool in_selection(const DesktopIcon *ic);
void move_selection(int x, int y, bool apply);
DesktopIcon *below_mouse(int px, int py);
void select_in_area(void);
void draw(void);
int handle(int event);
};
#endif

View File

@ -1,13 +1,21 @@
/*
* $Id$
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2008 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
@ -18,20 +26,19 @@
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/x.H>
#include <edelib/Debug.h>
#include <edelib/IconLoader.h>
#include <edelib/MenuItem.h>
#include <edelib/MessageBox.h>
#include <edelib/Nls.h>
#include <edelib/Run.h>
#include "ede-desktop.h"
#include "DesktopIcon.h"
#include "IconDialog.h"
#include "MovableIcon.h"
#include "Utils.h"
#include "Desktop.h"
/* label offset from icon y() + h(), so selection box can be drawn nicely */
#define LABEL_OFFSET 2
/* minimal icon sizes */
#define ICON_SIZE_MIN_W 48
@ -41,181 +48,160 @@
#define OFFSET_W 16
#define OFFSET_H 16
/* label offset from icon y()+h(), so selection box can be drawn nicely */
#define LABEL_OFFSET 2
EDELIB_NS_USING(String)
EDELIB_NS_USING(IconLoader)
EDELIB_NS_USING(MenuItem)
EDELIB_NS_USING(String)
EDELIB_NS_USING(MenuButton)
EDELIB_NS_USING(ICON_SIZE_HUGE)
EDELIB_NS_USING(ICON_SIZE_TINY)
EDELIB_NS_USING(input)
EDELIB_NS_USING(ask)
EDELIB_NS_USING(MenuItem)
EDELIB_NS_USING(run_async)
EDELIB_NS_USING(ask)
EDELIB_NS_USING(alert)
EDELIB_NS_USING(input)
EDELIB_NS_USING(ICON_SIZE_TINY)
EDELIB_NS_USING(ICON_SIZE_HUGE)
static void open_cb(Fl_Widget*, void* d);
static void rename_cb(Fl_Widget*, void* d);
static void edit_cb(Fl_Widget*, void* d);
static void delete_cb(Fl_Widget*, void* d);
static MenuItem icon_menu[] = {
{_("&Open"), 0, open_cb, 0},
{_("&Rename"), 0, rename_cb, 0},
{_("&Edit"), 0, edit_cb, 0},
{_("&Delete"), 0, delete_cb, 0},
/* {_("&Properties"), 0, props_cb, 0}, */
{0}
};
#if 0
static MenuItem icon_trash_menu[] = {
{_("&Open"), 0, 0},
{_("&Properties"), 0, 0, 0, FL_MENU_DIVIDER},
{_("&Empty"), 0, 0},
{0}
};
#endif
static void open_cb(Fl_Widget*, void* d) {
DesktopIcon* di = (DesktopIcon*)d;
IconSettings* s = di->get_settings();
run_async("ede-launch %s", s->cmd.c_str());
DesktopIcon *o = (DesktopIcon*)d;
/* run .desktop file directly, since it can contain startup details */
run_async("ede-launch %s", o->get_path());
}
static void rename_cb(Fl_Widget*, void* d) {
DesktopIcon* di = (DesktopIcon*)d;
static void edit_cb(Fl_Widget*, void* d) {
DesktopIcon *di = (DesktopIcon*)d;
((Desktop*)di->parent())->edit_icon(di);
}
const char* new_name = input(_("Change desktop icon name to:"), di->label());
# if 0
static void rename_cb(Fl_Widget*, void* d) {
DesktopIcon *di = (DesktopIcon*)d;
const char *new_name = input(_("Change desktop icon name to:"), di->label());
if(new_name) {
di->rename(new_name);
Desktop::instance()->rename_icon(di, new_name);
bool saved = ((Desktop*)di->parent())->rename_icon(di, new_name);
if(!saved)
alert(_("Unable to rename this icon. Please check if you have enough permissions to do so"));
}
}
#endif
static void delete_cb(Fl_Widget*, void* d) {
DesktopIcon* di = (DesktopIcon*)d;
DesktopIcon *di = (DesktopIcon*)d;
if(ask(_("This icon will be permanently deleted. Proceed?")))
Desktop::instance()->remove_icon(di, true);
if(ask(_("This icon will be permanently deleted. Are you sure?")))
((Desktop*)di->parent())->remove_icon(di, true);
}
/*
static void props_cb(Fl_Widget*, void* d) {
DesktopIcon* di = (DesktopIcon*)d;
icon_dialog_icon_property(di);
}
*/
DesktopIcon::DesktopIcon(GlobalIconSettings* gs, IconSettings* is, int bg) :
Fl_Widget(is->x, is->y, ICON_SIZE_MIN_W, ICON_SIZE_MIN_H) {
E_ASSERT(gs != NULL);
lwidth = lheight = 0;
focus = false;
micon = NULL;
darker_img = NULL;
gsettings = gs;
settings = is;
label(settings->name.c_str());
imenu = new MenuButton(0, 0, 0, 0);
if(settings->type == ICON_TRASH)
imenu->menu(icon_trash_menu);
else {
icon_menu[2].image(IconLoader::get("edit-delete", ICON_SIZE_TINY));
imenu->menu(icon_menu);
}
load_icon(ICON_FACE_ONE);
fix_position(x(), y());
/* use desktop color as color for icon background */
color(bg);
DesktopIcon::DesktopIcon(const char *l, int W, int H) : Fl_Widget(1, 1, W, H, l) {
box(FL_FLAT_BOX);
color(FL_RED);
label(l);
align(FL_ALIGN_WRAP);
update_label_font_and_size();
/* default values unless given explicitly */
labelfont(FL_HELVETICA);
labelsize(12);
darker_img = 0;
micon = 0;
lwidth = lheight = 0;
focused = false;
imenu = 0;
icon_menu[2].image((Fl_Image*)IconLoader::get("edit-delete", ICON_SIZE_TINY));
}
DesktopIcon::~DesktopIcon() {
E_DEBUG("DesktopIcon::~DesktopIcon()\n");
delete settings;
delete micon;
DesktopIcon::~DesktopIcon() {
delete darker_img;
delete micon;
delete imenu;
}
void DesktopIcon::load_icon(int face) {
const char* ic = NULL;
void DesktopIcon::set_image(const char *name) {
E_RETURN_IF_FAIL(IconLoader::inited());
if(face != ICON_FACE_TWO) {
if(!settings->icon.empty())
ic = settings->icon.c_str();
} else {
if(!settings->icon2.empty())
ic = settings->icon2.c_str();
}
if(!ic)
return;
if(!IconLoader::set(this, ic, ICON_SIZE_HUGE)) {
E_DEBUG(E_STRLOC ": Unable to load %s icon\n", ic);
return;
}
/* if not name give, use false name to trick IconLoader to use fallback icons */
if(!name) name = "THIS-ICON-DOES-NOT-EXISTS";
E_RETURN_IF_FAIL(IconLoader::set(this, name, ICON_SIZE_HUGE));
/* fetch image object for sizes */
Fl_Image* img = image();
Fl_Image *img = image();
int img_w = img->w();
int img_h = img->h();
int img_w = img->w(),
img_h = img->h();
/* resize box if icon is larger */
if(img_w > ICON_SIZE_MIN_W || img_h > ICON_SIZE_MIN_H)
size(img_w + OFFSET_W, img_h + OFFSET_H);
}
/* darker icon version for selection */
delete darker_img;
darker_img = img->copy(img->w(), img->h());
darker_img->color_average(FL_BLUE, 0.6);
void DesktopIcon::set_tooltip(const char *tip) {
#if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 3)
copy_tooltip(tip);
#else
/*
* in versions prior 1.3, copy_tooltip didn't exist and there wasn't any
* way to store tooltip without manually managing the storage
*/
if(tip) {
ttip = tip;
tooltip(ttip.c_str());
} else {
tooltip(tip);
}
#endif
}
void DesktopIcon::update_label_font_and_size(void) {
labelfont(gsettings->label_font);
labelsize(gsettings->label_fontsize);
lwidth = gsettings->label_maxwidth;
lheight= 0;
E_RETURN_IF_FAIL(opts != 0);
labelfont(opts->label_font);
labelsize(opts->label_fontsize);
lwidth = opts->label_maxwidth;
lheight = 0;
/*
* make sure current font size/type is set (internaly to fltk)
* so fl_measure() can correctly calculate label width and height
*/
int old = fl_font();
int old_sz = fl_size();
int old = fl_font(), old_sz = fl_size();
fl_font(labelfont(), labelsize());
fl_measure(label(), lwidth, lheight, align());
fl_font(old, old_sz);
lwidth += 12;
lwidth += 12;
lheight += 5;
}
void DesktopIcon::fix_position(int X, int Y) {
int dx, dy, dw, dh;
Desktop::instance()->area(dx, dy, dw, dh);
int dx = parent()->x(),
dy = parent()->y(),
dw = parent()->w(),
dh = parent()->h();
if(X < dx)
X = dx;
if(Y < dy)
Y = dy;
if(X + w() > dw)
X = (dx + dw) - w();
if(Y + h() > dh)
Y = (dy + dh) - h();
if(X < dx) X = dx;
if(Y < dy) Y = dy;
if(X + w() > dw) X = (dx + dw) - w();
if(Y + h() > dh) Y = (dy + dh) - h();
position(X, Y);
}
@ -227,14 +213,17 @@ void DesktopIcon::drag(int x, int y, bool apply) {
/*
* This is used to calculate correct window startup/ending
* position since icon is placed in the middle of the box.
*
* Opposite, window (shaped) will have small but noticeable 'jump off' and
* dropped icon position will not be at the exact place where was dropped.
*/
int ix = 0, iy = 0;
if(image()) {
ix = (w()/2) - (image()->w()/2);
iy = (h()/2) - (image()->h()/2);
/* include parent offset since x/y are absolute locations */
if(parent()) {
ix += parent()->x();
iy += parent()->y();
}
}
micon->position(micon->x() + ix, micon->y() + iy);
@ -251,7 +240,14 @@ void DesktopIcon::drag(int x, int y, bool apply) {
if(image()) {
ix = (w()/2) - (image()->w()/2);
iy = (h()/2) - (image()->h()/2);
/* also take into account offsets, as below we subtract it */
if(parent()) {
ix += parent()->x();
iy += parent()->y();
}
}
fix_position(micon->x() - ix, micon->y() - iy);
#else
fix_position(micon->x(), micon->y());
@ -276,38 +272,7 @@ int DesktopIcon::drag_icon_y(void) {
else
return micon->y();
}
void DesktopIcon::rename(const char* str) {
if(!str ||(str[0] == '\0'))
return;
if(settings->name == str)
return;
settings->name = str;
label(settings->name.c_str());
update_label_font_and_size();
redraw();
}
const String& DesktopIcon::path(void) {
return settings->full_path;
}
int DesktopIcon::icon_type(void) {
return settings->type;
}
void DesktopIcon::use_icon1(void) {
load_icon(ICON_FACE_ONE);
fast_redraw();
}
void DesktopIcon::use_icon2(void) {
load_icon(ICON_FACE_TWO);
fast_redraw();
}
void DesktopIcon::fast_redraw(void) {
int wsz = w();
int xpos = x();
@ -321,11 +286,9 @@ void DesktopIcon::fast_redraw(void) {
parent()->damage(FL_DAMAGE_ALL, xpos, y(), wsz, h() + lheight + LABEL_OFFSET + 2);
}
void DesktopIcon::draw(void) {
// draw_box(FL_UP_BOX, FL_BLACK);
void DesktopIcon::draw(void) {
if(image() && (damage() & FL_DAMAGE_ALL)) {
Fl_Image* im = image();
Fl_Image *im = image();
/* center image in the box */
int ix = (w()/2) - (im->w()/2);
@ -333,23 +296,27 @@ void DesktopIcon::draw(void) {
ix += x();
iy += y();
/* darker_img is always present if image() is present */
if(is_focused())
if(is_focused()) {
/* create darker image only when needed */
if(!darker_img) {
darker_img = im->copy(im->w(), im->h());
darker_img->color_average(FL_BLUE, 0.6);
}
darker_img->draw(ix, iy);
else
} else {
im->draw(ix, iy);
E_DEBUG(E_STRLOC ": DesktopIcon icon redraw\n");
}
}
if(gsettings->label_draw && (damage() & (FL_DAMAGE_ALL | EDAMAGE_CHILD_LABEL))) {
if(opts && opts->label_visible && (damage() & (FL_DAMAGE_ALL | EDE_DESKTOP_DAMAGE_CHILD_LABEL))) {
int X = x() + w()-(w()/2)-(lwidth/2);
int Y = y() + h() + LABEL_OFFSET;
Fl_Color old = fl_color();
if(!gsettings->label_transparent) {
fl_color(gsettings->label_background);
if(!opts->label_transparent) {
fl_color(opts->label_background);
fl_rectf(X, Y, lwidth, lheight);
}
@ -358,12 +325,12 @@ void DesktopIcon::draw(void) {
/* draw with icon's font */
fl_font(labelfont(), labelsize());
/* pseudo-shadow */
fl_color(FL_BLACK);
fl_draw(label(), X+1, Y+1, lwidth, lheight, align(), 0, 0);
fl_color(gsettings->label_foreground);
fl_color(opts->label_foreground);
fl_draw(label(), X, Y, lwidth, lheight, align(), 0, 0);
/* restore old font */
@ -371,7 +338,7 @@ void DesktopIcon::draw(void) {
if(is_focused()) {
/* draw focused box on our way so later this can be used to draw customised boxes */
fl_color(gsettings->label_foreground);
fl_color(opts->label_foreground);
fl_line_style(FL_DOT);
fl_push_matrix();
@ -390,7 +357,6 @@ void DesktopIcon::draw(void) {
/* revert to old color whatever that be */
fl_color(old);
E_DEBUG(E_STRLOC ": DesktopIcon label redraw\n");
}
}
@ -400,22 +366,34 @@ int DesktopIcon::handle(int event) {
case FL_UNFOCUS:
case FL_ENTER:
case FL_LEAVE:
return 1;
/* We have to handle FL_MOVE too, if want to get only once FL_ENTER when entered or FL_LEAVE when leaved */
case FL_MOVE:
return 1;
case FL_PUSH:
if(Fl::event_button() == 3) {
/* MenuItem::popup() by default does not call callbacks */
const MenuItem* m = imenu->menu()->popup(Fl::event_x(), Fl::event_y());
/*
* init icon specific menu only when needed
* TODO: since menu for all icons is mostly the same, it can be shared; Desktop can
* have menu instance seeded to all icons
*/
if(!imenu) {
imenu = new MenuButton(0, 0, 0, 0);
imenu->menu(icon_menu);
}
/* MenuItem::popup() by default does not call callbacks */
const MenuItem *m = imenu->menu()->popup(Fl::event_x(), Fl::event_y());
/* call menu callbacks, passing correct parameters */
if(m && m->callback())
m->do_callback(0, this);
}
return 1;
case FL_RELEASE:
if(Fl::event_clicks() > 0)
run_async("ede-launch %s", settings->cmd.c_str());
if(Fl::event_clicks() > 0 && !path.empty())
run_async("ede-launch %s", path.c_str());
return 1;
case FL_DND_ENTER:

View File

@ -1,95 +1,139 @@
/*
* $Id$
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2008 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __DESKTOPICON_H__
#define __DESKTOPICON_H__
#ifndef __DESKTOP_ICON_H__
#define __DESKTOP_ICON_H__
#include <FL/Fl_Widget.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Image.H>
#include <edelib/String.h>
#include <edelib/MenuButton.h>
#include <edelib/String.h>
#include "Globals.h"
enum {
DESKTOP_ICON_TYPE_NORMAL,
DESKTOP_ICON_TYPE_TRASH,
DESKTOP_ICON_TYPE_LINK,
DESKTOP_ICON_TYPE_FILE,
DESKTOP_ICON_TYPE_FOLDER
};
/* default icon sizes */
#define DESKTOP_ICON_SIZE_W 48
#define DESKTOP_ICON_SIZE_H 48
/*
* Each DesktopIcon shares IconOptions, which is content of [Icons] section
* from configuration file. With this, 'Desktop' needs only to update content so all
* icons see it.
*/
struct IconOptions {
int label_background;
int label_foreground;
int label_font;
int label_fontsize;
int label_maxwidth;
int label_transparent;
int label_visible;
bool one_click_exec;
IconOptions() {
label_background = FL_BLACK;
label_foreground = FL_WHITE;
label_maxwidth = 75;
label_transparent = 1;
label_visible = 1;
label_font = FL_HELVETICA;
label_fontsize = 12;
one_click_exec = false;
}
/* should be called only when values are assigned to fonts */
void sanitize_font(void) {
if(label_font < 0) label_font = FL_HELVETICA;
if(label_fontsize < 8) label_fontsize = 12;
if(label_maxwidth < 30) label_maxwidth = 75;
}
};
class GlobalIconSettings;
class IconSettings;
class MovableIcon;
class DesktopIcon : public Fl_Widget {
private:
IconSettings* settings;
const GlobalIconSettings* gsettings;
int icon_type;
int lwidth, lheight;
bool focused;
int lwidth;
int lheight;
bool focus;
Fl_Image *darker_img;
IconOptions *opts;
MovableIcon *micon;
MovableIcon* micon;
/* location of .desktop file */
EDELIB_NS_PREPEND(String) path;
EDELIB_NS_PREPEND(MenuButton) *imenu;
Fl_Image* darker_img;
edelib::MenuButton* imenu;
void load_icon(int face);
void update_label_font_and_size(void);
void fix_position(int X, int Y);
#if !((FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 3))
EDELIB_NS_PREPEND(String) ttip;
#endif
public:
DesktopIcon(GlobalIconSettings* gisett, IconSettings* isett, int bg);
DesktopIcon(const char *l, int W = DESKTOP_ICON_SIZE_W, int H = DESKTOP_ICON_SIZE_H);
~DesktopIcon();
virtual void draw(void);
virtual int handle(int event);
void set_icon_type(int c) { icon_type = c; }
int get_icon_type(void) { return icon_type;}
void set_image(const char *name);
void set_tooltip(const char *tip);
void update_label_font_and_size(void);
void set_options(IconOptions *o) {
opts = o;
update_label_font_and_size();
}
/* Here is implemented localy focus schema avoiding messy fltk one. Focus/unfocus is handled from Desktop. */
void do_focus(void) { focused = true; }
void do_unfocus(void) { focused = false; }
bool is_focused(void) { return focused; }
void set_path(const char *p) { path = p; }
const char *get_path(void) { return path.c_str(); }
void fix_position(int X, int Y);
void drag(int x, int y, bool apply);
int drag_icon_x(void);
int drag_icon_y(void);
IconSettings* get_settings(void) { return settings; }
/*
* This is 'enhanced' (in some sense) redraw(). Redrawing
* icon will not fully redraw label nor focus box, which laid outside
* icon box. It will use damage() on given region, but called from
* parent, so parent can redraw that region on itself (since label does
* not laid on any box)
* This is 'enhanced' (in some sense) redraw(). Redrawing icon will not fully redraw label nor
* focus box, which laid outside icon box. It will use damage() on given region, but called from
* parent, so parent can redraw that region on itself (since label does not laid on any box)
*
* Alternative way would be to redraw whole parent, but it is pretty unneeded
* and slow.
* Alternative way would be to redraw the whole parent, but it is pretty unneeded and slow.
*/
void fast_redraw(void);
/*
* Here is implemented localy focus schema avoiding
* messy fltk one. Focus/unfocus is handled from Desktop.
*/
void do_focus(void) { focus = true; }
void do_unfocus(void) { focus = false; }
bool is_focused(void) { return focus; }
Fl_Image* icon_image(void) { return image(); }
void rename(const char* str);
/*
* make sure this returns String since operator== is
* further used, especially in Desktop
*/
const edelib::String& path(void);
int icon_type(void);
void use_icon1(void);
void use_icon2(void);
void draw(void);
int handle(int event);
};
#endif

35
ede-desktop/Globals.h Normal file
View File

@ -0,0 +1,35 @@
/*
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* Copyright (C) 2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __EDE_DESKTOP_GLOBAL_H__
#define __EDE_DESKTOP_GLOBAL_H__
#include <edelib/Resource.h>
/* alias it so we don't have to use EDELIB_NS_PREPEND */
EDELIB_NS_USING_AS(Resource, DesktopConfig)
#define EDE_DESKTOP_DAMAGE_CHILD_LABEL 0x10
#define EDE_DESKTOP_DAMAGE_OVERLAY 0x20
#define EDE_DESKTOP_DAMAGE_CLEAR_OVERLAY 0x30
#define EDE_DESKTOP_DESKTOP_EXT ".desktop"
#endif

View File

@ -1,16 +1,25 @@
/*
* $Id: IconProperties.h 2366 2008-10-02 09:42:19Z karijes $
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2012 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2014 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <ctype.h>
#include <limits.h>
#include <FL/Fl_Window.H>
#include <FL/Fl.H>
@ -20,6 +29,9 @@
#include <FL/Fl_Menu_Item.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_File_Chooser.H>
#include <FL/Fl_Tabs.H>
#include <FL/Fl_Group.H>
#include <FL/Fl_Check_Button.H>
#include <edelib/Nls.h>
#include <edelib/String.h>
@ -35,19 +47,22 @@
#include "IconDialog.h"
#include "DesktopIcon.h"
#include "ede-desktop.h"
#include "Desktop.h"
#include "Globals.h"
EDELIB_NS_USING_LIST(10, (str_tolower, icon_chooser, dir_home, build_filename, alert,
EDELIB_NS_USING_LIST(12, (str_tolower, icon_chooser, dir_home, build_filename, alert, ask, file_remove,
ICON_SIZE_HUGE, String, IconLoader, DesktopFile, DESK_FILE_TYPE_APPLICATION))
#define DEFAULT_ICON "empty"
/* it is safe to be globals */
static Fl_Window *win;
static Fl_Button *img, *browse, *ok, *cancel;
static Fl_Input *name, *comment, *execute;
static Fl_Choice *icon_type;
static String img_path;
static Fl_Window *win;
static Fl_Button *img, *browse, *ok, *cancel;
static Fl_Input *name, *comment, *execute, *workdir;
static Fl_Choice *icon_type;
static Fl_Check_Button *run_in_terminal, *start_notify;
static String img_path, old_desktop_path;
static DesktopIcon *curr_icon;
/* the only supported type for now is application */
static Fl_Menu_Item menu_items[] = {
@ -59,8 +74,9 @@ static bool is_empty(const char *str) {
if(!str) return true;
const char *p = str;
while(*p++)
while(*p++) {
if(!isspace(*p)) return false;
}
return true;
}
@ -73,13 +89,15 @@ static void cancel_cb(Fl_Widget*, void*) {
win->hide();
}
static void ok_cb(Fl_Widget*, void*) {
static void ok_cb(Fl_Widget*, void *d) {
if(is_empty_input(name) || is_empty_input(execute) || !img->image()) {
/* do nothing */
win->hide();
return;
}
Desktop *self = (Desktop*)d;
DesktopFile df;
df.create_new(DESK_FILE_TYPE_APPLICATION);
df.set_name(name->value());
@ -87,106 +105,170 @@ static void ok_cb(Fl_Widget*, void*) {
if(comment->value())
df.set_comment(comment->value());
if(!img_path.empty() && img_path.length() > 1) {
/* figure out basename */
const char *s;
char *p, *e;
s = img_path.c_str();
p = (char*)strrchr(s, E_DIR_SEPARATOR);
if(p && *p++) {
/* now remove extension */
e = (char*)strrchr((const char*)p, '.');
if(e) *e = '\0';
df.set_icon(p);
}
} else {
df.set_icon(DEFAULT_ICON);
}
df.set_icon((img_path.length() > 1) ? img_path.c_str() : DEFAULT_ICON);
df.set_exec(execute->value());
if(!is_empty_input(workdir))
df.set_path(workdir->value());
df.set_startup_notify(start_notify->value());
df.set_terminal(run_in_terminal->value());
/* determine filename and save it */
String file = name->value();
const char *fp = file.c_str();
str_tolower((unsigned char*)fp);
file += ".desktop";
file += EDE_DESKTOP_DESKTOP_EXT;
/* go through the file and replace spaces with '_' */
for(char *p = (char*)file.c_str(); p && *p; p++)
if(isspace(*p)) *p = '_';
for(String::size_type i = 0; i < file.length(); i++)
if(isspace(file[i])) file[i] = '_';
/* TODO: let 'Desktop' (class) returns full desktop path */
String path = build_filename(Desktop::instance()->desktop_path(), file.c_str());
/*
* disable watching on folder and explicitly add file (probably as notification will be fired up faster than
* file will be available on that location)
*/
Desktop::instance()->dir_watch_off();
String path = build_filename(self->desktop_path(), file.c_str());
int X = 0, Y = 0;
if(curr_icon) {
X = curr_icon->x();
Y = curr_icon->y();
/* try to remove icon from filesystem only when we can't overwrite old icon path */
self->remove_icon(curr_icon, old_desktop_path != path);
}
if(df.save(path.c_str())) {
/* explictly add file path */
Desktop::instance()->add_icon_by_path(path.c_str(), NULL);
/*
* wait a second; this would remove event from the queue so watched does not complain how filed
* does not exists
DesktopIcon *ic = self->read_desktop_file(path.c_str(), file.c_str());
if(ic) {
if(X > 0 || Y > 0) ic->position(X, Y);
self->add(ic);
}
self->redraw();
/*
* In case when we rename icon, icon position will not be saved (because they are saved by icon basename). So
* with different paths we are assured the name was changed and we proceed further.
*/
Fl::wait(1);
Desktop::instance()->redraw();
if(old_desktop_path != path) self->save_icons_positions();
} else {
alert(_("Unable to create '%s' file. Received error is: %s\n"), path.c_str(), df.strerror());
}
Desktop::instance()->dir_watch_on();
win->hide();
}
static void img_browse_cb(Fl_Widget*, void*) {
img_path = icon_chooser(ICON_SIZE_HUGE);
if(img_path.empty()) return;
Fl_Image* im = Fl_Shared_Image::get(img_path.c_str());
if(!im) return;
img->image(im);
img->redraw();
if(!img_path.empty())
IconLoader::set(img, img_path.c_str(), ICON_SIZE_HUGE);
}
static void file_browse_cb(Fl_Widget*, void*) {
const char *p = fl_file_chooser(_("Choose program path to execute"), "*", 0, 0);
if(!p) return;
execute->value(p);
if(p) execute->value(p);
}
void icon_dialog_icon_create(void) {
win = new Fl_Window(430, 170, _("Create desktop icon"));
img = new Fl_Button(10, 10, 75, 75);
img->callback(img_browse_cb);
img->tooltip(_("Click to select icon"));
IconLoader::set(img, DEFAULT_ICON, ICON_SIZE_HUGE);
name = new Fl_Input(205, 10, 215, 25, _("Name:"));
comment = new Fl_Input(205, 40, 215, 25, _("Comment:"));
execute = new Fl_Input(205, 70, 185, 25, _("Execute:"));
browse = new Fl_Button(395, 70, 25, 25, "...");
browse->callback(file_browse_cb);
icon_type = new Fl_Choice(205, 100, 215, 25, _("Type:"));
icon_type->down_box(FL_BORDER_BOX);
icon_type->menu(menu_items);
static void dir_browse_cb(Fl_Widget*, void*) {
const char *p = fl_dir_chooser(_("Choose directory"), "*", 0);
if(p) workdir->value(p);
}
#define BUFSIZE PATH_MAX
void icon_dialog_icon_edit(Desktop *self, DesktopIcon *d) {
const char *lbl = d ? _("Edit desktop icon") : _("Create desktop icon");
DesktopFile *df = NULL;
char *buf = NULL;
old_desktop_path = "";
curr_icon = d;
if(d) {
df = new DesktopFile();
if(!df->load(d->get_path())) {
delete df;
df = NULL;
int ret = ask(_("Unable to load .desktop file for this icon. Would you like to create a new icon instead?"));
if(!ret) return;
/* force NULL on icon, so we can run dialog in 'create' mode */
d = NULL;
}
buf = new char[BUFSIZE];
old_desktop_path = d->get_path();
}
win = new Fl_Window(450, 220, lbl);
Fl_Tabs *tabs = new Fl_Tabs(10, 10, 430, 165);
tabs->begin();
Fl_Group *g1 = new Fl_Group(15, 30, 415, 140, _("Basic"));
g1->begin();
img = new Fl_Button(20, 45, 80, 75);
img->callback(img_browse_cb);
img->tooltip(_("Click to select icon"));
if(d) {
E_ASSERT(df != NULL);
if(df->icon(buf, BUFSIZE)) {
IconLoader::set(img, buf, ICON_SIZE_HUGE);
img_path = buf;
}
}
/* handles even the case when we are creating the new icon */
if(!img->image()) {
IconLoader::set(img, DEFAULT_ICON, ICON_SIZE_HUGE);
img_path = DEFAULT_ICON;
}
name = new Fl_Input(210, 45, 215, 25, _("Name:"));
if(d && df->name(buf, BUFSIZE)) name->value(buf);
comment = new Fl_Input(210, 75, 215, 25, _("Comment:"));
if(d && df->comment(buf, BUFSIZE)) comment->value(buf);
execute = new Fl_Input(210, 105, 185, 25, _("Execute:"));
if(d && df->exec(buf, BUFSIZE)) execute->value(buf);
browse = new Fl_Button(400, 105, 25, 25, "...");
browse->callback(file_browse_cb);
icon_type = new Fl_Choice(210, 135, 215, 25, _("Type:"));
icon_type->down_box(FL_BORDER_BOX);
icon_type->menu(menu_items);
g1->end();
Fl_Group *g2 = new Fl_Group(15, 30, 420, 140, _("Details"));
g2->hide();
g2->begin();
run_in_terminal = new Fl_Check_Button(195, 80, 235, 25, _("Run in terminal"));
run_in_terminal->down_box(FL_DOWN_BOX);
if(df) run_in_terminal->value(df->terminal());
workdir = new Fl_Input(195, 45, 205, 25, _("Working directory:"));
if(df && df->path(buf, BUFSIZE)) workdir->value(buf);
Fl_Button *browsedir = new Fl_Button(405, 45, 25, 25, "...");
browsedir->callback(dir_browse_cb);
start_notify = new Fl_Check_Button(195, 110, 235, 25, _("Use startup notification"));
start_notify->down_box(FL_DOWN_BOX);
if(df) start_notify->value(df->startup_notify());
g2->end();
tabs->end();
ok = new Fl_Button(255, 185, 90, 25, _("&OK"));
ok->callback(ok_cb, self);
cancel = new Fl_Button(350, 185, 90, 25, _("&Cancel"));
cancel->callback(cancel_cb);
ok = new Fl_Button(235, 135, 90, 25, _("&OK"));
ok->callback(ok_cb);
cancel = new Fl_Button(330, 135, 90, 25, _("&Cancel"));
cancel->callback(cancel_cb);
win->end();
win->set_modal();
delete df;
delete buf;
Fl::focus(name);
win->show();
}
void icon_dialog_icon_property(DesktopIcon *d) {
}
}

View File

@ -1,21 +1,30 @@
/*
* $Id: IconProperties.h 2366 2008-10-02 09:42:19Z karijes $
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2012 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __ICONDIALOG_H__
#define __ICONDIALOG_H__
class DesktopIcon;
class Desktop;
void icon_dialog_icon_create(void);
void icon_dialog_icon_property(DesktopIcon *d);
void icon_dialog_icon_edit(Desktop *self, DesktopIcon *di);
inline void icon_dialog_icon_create(Desktop *d) { icon_dialog_icon_edit(d, NULL); }
#endif

View File

@ -1,26 +1,34 @@
#
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2000-2007 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
# Copyright (C) 2006-2013 Sanel Zukan
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
SubDir TOP ede-desktop ;
ObjectC++Flags ede-desktop.cpp : -DUSE_EDELIB_WINDOW ;
SOURCE = ede-desktop.cpp
Utils.cpp
Wallpaper.cpp
DesktopIcon.cpp
Wallpaper.cpp
DesktopIcon.cpp
MovableIcon.cpp
IconDialog.cpp ;
Utils.cpp
IconDialog.cpp
Desktop.cpp ;
ObjectC++Flags $(SOURCE) : $(EDELIB_DBUS_INCLUDE) ;
EdeProgram ede-desktop : $(SOURCE) ;
LinkAgainst ede-desktop : $(EDELIB_DBUS_LIB) ;
TranslationStrings locale : $(SOURCE) ;
LinkAgainst ede-desktop : $(EDELIB_DBUS_LIB) $(XSHAPE_LIBS) $(PTHREAD_LIBS) ;

View File

@ -1,13 +1,21 @@
/*
* $Id: DesktopIcon.cpp 3032 2011-08-03 12:20:37Z karijes $
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2011 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
@ -15,8 +23,9 @@
#endif
#define FL_LIBRARY 1
#include <FL/Fl.H>
#include <FL/x.H>
#include <FL/Fl_Image.H>
#include <edelib/Debug.h>
#ifdef HAVE_SHAPE
@ -27,7 +36,9 @@
#include "DesktopIcon.h"
#include "Utils.h"
MovableIcon::MovableIcon(DesktopIcon* ic) : Fl_Window(ic->x(), ic->y(), ic->w(), ic->h()), icon(ic), mask(0), opacity_atom(0) {
MovableIcon::MovableIcon(DesktopIcon* ic) :
Fl_Window(ic->x(), ic->y(), ic->w(), ic->h()), icon(ic), mask(0), opacity_atom(0)
{
E_ASSERT(icon != NULL);
set_override();
@ -36,7 +47,7 @@ MovableIcon::MovableIcon(DesktopIcon* ic) : Fl_Window(ic->x(), ic->y(), ic->w(),
begin();
/* force box be same width/height as icon so it can fit inside masked window */
#ifdef HAVE_SHAPE
Fl_Image* img = ic->icon_image();
Fl_Image* img = ic->image();
if(img)
icon_box = new Fl_Box(0, 0, img->w(), img->h());
else
@ -44,7 +55,7 @@ MovableIcon::MovableIcon(DesktopIcon* ic) : Fl_Window(ic->x(), ic->y(), ic->w(),
#else
icon_box = new Fl_Box(0, 0, w(), h());
#endif
icon_box->image(ic->icon_image());
icon_box->image(ic->image());
end();
opacity_atom = XInternAtom(fl_display, "_NET_WM_WINDOW_OPACITY", False);
@ -60,8 +71,8 @@ void MovableIcon::show(void) {
Fl_X::make_xid(this);
#ifdef HAVE_SHAPE
if(icon->icon_image()) {
mask = create_mask(icon->icon_image());
if(icon->image()) {
mask = create_mask(icon->image());
if(mask) {
XShapeCombineMask(fl_display, fl_xid(this), ShapeBounding, 0, 0, mask, ShapeSet);

View File

@ -1,21 +1,29 @@
/*
* $Id: DesktopIcon.h 2742 2009-07-09 13:59:51Z karijes $
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2011 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MOVABLEICON_H__
#define __MOVABLEICON_H__
#include <X11/Xlib.h> // Pixmap
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/x.H>
class DesktopIcon;
@ -25,6 +33,7 @@ private:
Fl_Box* icon_box;
Pixmap mask;
Atom opacity_atom;
public:
MovableIcon(DesktopIcon* i);
~MovableIcon();

View File

@ -1,17 +1,24 @@
/*
* $Id$
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2008 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <string.h>
#include <FL/x.H>
#include <edelib/Debug.h>
#include "Utils.h"
@ -26,8 +33,7 @@ static Fl_Window* overlay_drawable = NULL;
static char dash_list[] = {1};
void draw_overlay_rect(void) {
if(overlay_w <= 0 || overlay_h <= 0)
return;
E_RETURN_IF_FAIL(overlay_w > 0 && overlay_h > 0);
XSetDashes(fl_display, fl_gc, 0, dash_list, 1);
XSetLineAttributes(fl_display, fl_gc, 2, LineOnOffDash, CapButt, JoinMiter);
@ -35,11 +41,7 @@ void draw_overlay_rect(void) {
XSetFunction(fl_display, fl_gc, GXxor);
XSetForeground(fl_display, fl_gc, 0xffffffff);
Window ow;
if(overlay_drawable)
ow = fl_xid(overlay_drawable);
else
ow = fl_window;
Window ow = overlay_drawable ? fl_xid(overlay_drawable) : fl_window;
XDrawRectangle(fl_display, ow, fl_gc, overlay_x, overlay_y, overlay_w-1, overlay_h-1);
XSetFunction(fl_display, fl_gc, GXcopy);

View File

@ -1,25 +1,31 @@
/*
* $Id$
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2008 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __UTILS_H__
#define __UTILS_H__
#include <X11/Xlib.h>
#include <FL/Fl_Window.H>
#include <FL/Fl_Image.H>
#include <FL/x.H>
void draw_xoverlay(int x, int y, int w, int h);
void clear_xoverlay(void);
void set_xoverlay_drawable(Fl_Window* win);
Pixmap create_mask(Fl_Image* img);

View File

@ -1,52 +1,53 @@
/*
* $Id$
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2009 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <string.h> // memcpy
#include <stdlib.h> // malloc
#include <string.h>
#include <stdlib.h>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_RGB_Image.H>
#include <FL/fl_draw.H>
#include <FL/x.H>
#include <edelib/Debug.h>
#include "Wallpaper.h"
#include "Utils.h"
#define CALC_PIXEL(tmp, rshift, rmask, gshift, gmask, bshift, bmask) \
tmp = 0; \
if(rshift >= 0) \
tmp |= (((int)r << rshift) & rmask); \
else \
tmp |= (((int)r >> (-rshift)) & rmask); \
\
if(gshift >= 0) \
tmp |= (((int)g << gshift) & gmask); \
else \
tmp |= (((int)g >> (-gshift)) & gmask); \
\
if(bshift >= 0) \
tmp |= (((int)b << bshift) & bmask); \
else \
#define CALC_PIXEL(tmp, rshift, rmask, gshift, gmask, bshift, bmask) \
tmp = 0; \
if(rshift >= 0) \
tmp |= (((int)r << rshift) & rmask); \
else \
tmp |= (((int)r >> (-rshift)) & rmask); \
\
if(gshift >= 0) \
tmp |= (((int)g << gshift) & gmask); \
else \
tmp |= (((int)g >> (-gshift)) & gmask); \
\
if(bshift >= 0) \
tmp |= (((int)b << bshift) & bmask); \
else \
tmp |= (((int)b >> (-bshift)) & bmask)
static Pixmap create_xpixmap(Fl_Image* img, XImage** xim, Pixmap pix, int wp_w, int wp_h) {
if(!img)
return 0;
if(pix)
XFreePixmap(fl_display, pix);
if(!img) return 0;
if(pix) XFreePixmap(fl_display, pix);
unsigned long rmask = fl_visual->visual->red_mask;
unsigned long gmask = fl_visual->visual->green_mask;
@ -108,15 +109,9 @@ static Pixmap create_xpixmap(Fl_Image* img, XImage** xim, Pixmap pix, int wp_w,
int iw = img->w();
int ih = img->h();
int id = img->d();
bool msb = false;
if(ImageByteOrder(fl_display) == MSBFirst)
msb = true;
else
msb = false;
bool msb = (ImageByteOrder(fl_display) == MSBFirst) ? true : false;
unsigned int r, g, b, tmp;
//unsigned char* dest = (unsigned char*)malloc(sizeof(unsigned char) * iw * ih * id);
unsigned char* dest = (unsigned char*)malloc(ih * (*xim)->bytes_per_line);
unsigned char* destptr = dest;
unsigned char* src = (unsigned char*)img->data()[0];
@ -257,8 +252,8 @@ static Pixmap create_xpixmap(Fl_Image* img, XImage** xim, Pixmap pix, int wp_w,
*
* FIXME: drawable background should be the same color as wallpaper background
*/
Window drawable = XCreateSimpleWindow(fl_display, RootWindow(fl_display, fl_screen), 0, 0, wp_w,
wp_h, 0, 0, BlackPixel(fl_display, fl_screen));
Window drawable = XCreateSimpleWindow(fl_display, RootWindow(fl_display, fl_screen), 0, 0, wp_w, wp_h,
0, 0, BlackPixel(fl_display, fl_screen));
pix = XCreatePixmap(fl_display, drawable, wp_w, wp_h, fl_visual->depth);
@ -349,23 +344,18 @@ static void create_tile(Fl_Image* orig, Fl_RGB_Image** copied, int X, int Y, int
}
Wallpaper::~Wallpaper() {
if(rootpmap_pixmap)
XFreePixmap(fl_display, rootpmap_pixmap);
if(rootpmap_pixmap) XFreePixmap(fl_display, rootpmap_pixmap);
delete stretched_alloc;
}
void Wallpaper::set_rootpmap(void) {
if(!image())
return;
E_RETURN_IF_FAIL(image() != NULL);
XImage* rootpmap_image = 0;
XImage *rootpmap_image = 0;
Atom _XA_XROOTPMAP_ID;
rootpmap_pixmap = create_xpixmap(image(), &rootpmap_image, rootpmap_pixmap, w(), h());
if(!rootpmap_pixmap)
return;
E_RETURN_IF_FAIL(rootpmap_pixmap != 0);
/* XDestroyImage function calls frees both the image structure and the data pointed to by the image structure */
if(rootpmap_image)
@ -374,60 +364,63 @@ void Wallpaper::set_rootpmap(void) {
_XA_XROOTPMAP_ID = XInternAtom(fl_display, "_XROOTPMAP_ID", False);
XChangeProperty(fl_display, RootWindow(fl_display, fl_screen),
_XA_XROOTPMAP_ID, XA_PIXMAP, 32, PropModeReplace, (unsigned char *)&rootpmap_pixmap, 1);
_XA_XROOTPMAP_ID, XA_PIXMAP, 32, PropModeReplace, (unsigned char *)&rootpmap_pixmap, 1);
}
bool Wallpaper::load(const char* path, WallpaperState s) {
bool Wallpaper::load(const char *path, int s, bool rootpmap) {
E_ASSERT(path != NULL);
Fl_Shared_Image* i = Fl_Shared_Image::get(path);
if(!i)
return false;
Fl_Shared_Image *img = Fl_Shared_Image::get(path);
E_RETURN_VAL_IF_FAIL(img != NULL, false);
if(s != WALLPAPER_CENTER && s != WALLPAPER_TILE && s != WALLPAPER_STRETCH)
s = WALLPAPER_CENTER;
if(s == WALLPAPER_TILE) {
Fl_RGB_Image* tiled;
Fl_RGB_Image *tiled;
create_tile((Fl_Image*)i, &tiled, x(), y(), w(), h());
create_tile((Fl_Image*)img, &tiled, x(), y(), w(), h());
image(tiled);
} else if(s == WALLPAPER_STRETCH) {
Fl_Image* stretched = NULL;
Fl_Image *stretched = NULL;
if(i->w() == w() && i->h() == h())
stretched = i;
if(img->w() == w() && img->h() == h())
stretched = img;
else {
/* valgrind reports it as possible lost, but FLTK should free it */
delete stretched_alloc;
stretched = i->copy(w(), h());
i->release();
stretched = img->copy(w(), h());
img->release();
stretched_alloc = stretched;
}
image(stretched);
} else {
image(i);
image(img);
}
state = s;
/* set root pixmap for pseudo transparency */
set_rootpmap();
if(rootpmap) set_rootpmap();
state = s;
use_rootpmap = rootpmap;
/* prevent self assignment or bad things will happen */
if(wpath != path) wpath = path;
return true;
}
void Wallpaper::draw(void) {
if(!image())
return;
E_RETURN_IF_FAIL(image() != NULL);
int ix, iy, iw, ih;
Fl_Image* im = image();
iw = im->w();
ih = im->h();
if(iw == 0 || ih == 0)
return;
E_RETURN_IF_FAIL(iw > 0 && ih > 0);
if(state == WALLPAPER_CENTER) {
ix = (w()/2) - (iw/2);
@ -475,3 +468,20 @@ int Wallpaper::handle(int event) {
return 0;
}
void Wallpaper::resize(int X, int Y, int W, int H) {
if(X == x() && Y == y() && W == w() && H == h())
return;
Fl_Box::resize(X, Y, W, H);
if(image()) {
/*
* It is safe to call 'load()' again, as Fl_Shared_Image::get() will cache successfully loaded image.
* Also benefit is that image transormations (scaling, tiling) will be done again on original image, so
* there will be no lost data.
*
* TODO: Fl_Shared_Image will eat a memory; this needs some investigation.
*/
load(wpath.c_str(), state, use_rootpmap);
}
}

View File

@ -1,22 +1,31 @@
/*
* $Id$
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2009 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2006-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __WALLPAPER_H__
#define __WALLPAPER_H__
#include <X11/Xlib.h> // XImage, Pixmap
#include <FL/Fl_Box.H>
#include <FL/x.H>
#include <edelib/String.h>
enum WallpaperState {
enum {
WALLPAPER_CENTER,
WALLPAPER_STRETCH,
WALLPAPER_TILE
@ -26,21 +35,23 @@ class Fl_Image;
class Wallpaper : public Fl_Box {
private:
Pixmap rootpmap_pixmap;
WallpaperState state;
Fl_Image* stretched_alloc; /* FLTK issue */
Pixmap rootpmap_pixmap;
int state;
Fl_Image* stretched_alloc; /* FLTK issue */
bool use_rootpmap;
EDELIB_NS_PREPEND(String) wpath;
void set_rootpmap(void);
public:
Wallpaper(int X, int Y, int W, int H) : Fl_Box(X, Y, W, H),
rootpmap_pixmap(0), state(WALLPAPER_CENTER), stretched_alloc(NULL) { }
Wallpaper(int X, int Y, int W, int H) : Fl_Box(X, Y, W, H),
rootpmap_pixmap(0), state(WALLPAPER_CENTER), stretched_alloc(NULL), use_rootpmap(false) { }
~Wallpaper();
bool load(const char* path, WallpaperState s);
bool load(const char *path, int s, bool do_rootpmap = true);
virtual void draw(void);
virtual int handle(int event);
void draw(void);
int handle(int event);
void resize(int X, int Y, int W, int H);
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,174 +0,0 @@
/*
* $Id$
*
* ede-desktop, desktop and icon manager
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2006-2009 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
*/
#ifndef __EDE_DESKTOP_H__
#define __EDE_DESKTOP_H__
#ifdef USE_EDELIB_WINDOW
# include <edelib/Window.h>
# define EDE_DESKTOP_WINDOW edelib::Window
#else
# include <FL/Fl_Window.H>
# include <FL/Fl_Double_Window.H>
# define EDE_DESKTOP_WINDOW Fl_Window
#endif
#include <FL/Fl_Image.H>
#include <edelib/String.h>
#include <edelib/Resource.h>
#include <edelib/List.h>
#include <edelib/EdbusConnection.h>
#include <edelib/MenuButton.h>
#define EDAMAGE_CHILD_LABEL 0x10
#define EDAMAGE_OVERLAY 0x20
#define ICON_NORMAL 1 // .desktop file
#define ICON_TRASH 2 // trash.desktop (specific since have two icons for empty/full)
#define ICON_FILE 3 // real file
#define ICON_SYMLINK 4 // symbolic link
#define ICON_FACE_ONE 1 // use icon
#define ICON_FACE_TWO 2 // use icon2
struct GlobalIconSettings {
int label_background;
int label_foreground;
int label_font;
int label_fontsize;
int label_maxwidth;
bool label_transparent;
bool label_draw;
bool one_click_exec;
bool auto_arrange;
bool same_size;
};
/*
* Settings representing related to icon on desktop. To complicate our lives
* (and to, at least, simplify code) it can be:
* - .desktop file content (normal or trash like)
* - real file copied/moved inside ~/Desktop directory
* - symlink in ~/Desktop directory pointing to the real file
*/
struct IconSettings {
int x, y;
int type; // ICON_NORMAL, ICON_TRASH,...
bool cmd_is_url; // interpret cmd as url, like system:/,trash:/,$HOME
edelib::String name;
edelib::String cmd;
edelib::String icon;
edelib::String icon2; // for stateable icons, like trash (empty/full)
edelib::String key_name; // name used as key when storing positions
edelib::String full_path; // for tracking changes
};
/* selection overlay */
struct SelectionOverlay {
int x, y, w, h;
bool show;
};
class Wallpaper;
class DesktopIcon;
typedef edelib::list<DesktopIcon*> DesktopIconList;
typedef edelib::list<DesktopIcon*>::iterator DesktopIconListIter;
typedef edelib::list<edelib::String> StringList;
typedef edelib::list<edelib::String>::iterator StringListIter;
class Desktop : public EDE_DESKTOP_WINDOW {
private:
static Desktop* pinstance;
int selection_x, selection_y;
/* last recorded pointer position, so icon can be created at position where menu is clicked */
int last_px, last_py;
bool moving;
bool do_dirwatch;
edelib::String desktop_dir_path;
SelectionOverlay* selbox;
GlobalIconSettings* gisett;
edelib::MenuButton* dmenu;
Wallpaper* wallpaper;
edelib::EdbusConnection* dbus;
DesktopIconList icons;
DesktopIconList selectionbuf;
void init_internals(void);
void load_icons(const char* path);
void save_icons_positions(void);
IconSettings* read_desktop_file(const char* path);
void add_icon(DesktopIcon* ic);
DesktopIcon* find_icon_by_path(const char* path, DesktopIconListIter* pos);
bool remove_icon_by_path(const char* path);
void auto_arrange(void);
void unfocus_all(void);
void select(DesktopIcon* ic, bool do_redraw = true);
void select_only(DesktopIcon* ic);
bool in_selection(const DesktopIcon* ic);
void move_selection(int x, int y, bool apply);
void select_in_area(void);
//void dnd_drop_source(const char* src, int src_len, int x, int y);
DesktopIcon* below_mouse(int px, int py);
public:
Desktop();
~Desktop();
virtual void show(void);
virtual void hide(void);
virtual void draw(void);
virtual int handle(int event);
static void init(void);
static void shutdown(void);
static Desktop* instance(void);
void read_config(void);
bool add_icon_by_path(const char* path, edelib::Resource* conf);
bool remove_icon(DesktopIcon *d, bool real_delete);
bool rename_icon(DesktopIcon *d, const char *n);
void update_workarea(void);
void area(int& X, int& Y, int& W, int& H) { X = x(); Y = y(); W = w(); H = h(); }
void notify_desktop_changed(void);
void dir_watch(const char* dir, const char* changed, int flags);
void dir_watch_on(void) { do_dirwatch = true; }
void dir_watch_off(void) { do_dirwatch = false; }
const char *desktop_path(void) { return desktop_dir_path.c_str(); }
};
#endif

View File

@ -1,42 +1,72 @@
# data file for the Fltk User Interface Designer (fluid)
version 1.0300
version 1.0302
header_name {.h}
code_name {.cxx}
Function {} {open
} {
Fl_Window {} {open
xywh {474 344 430 170} type Double visible
xywh {426 288 450 220} type Double visible
} {
Fl_Button {} {
xywh {10 10 75 75}
}
Fl_Input {} {
label {Name:}
xywh {205 10 215 25}
}
Fl_Input {} {
label {Comment:}
xywh {205 40 215 25}
}
Fl_Input {} {
label {Execute:} selected
xywh {205 70 185 25}
}
Fl_Button {} {
label {...}
xywh {395 70 25 25}
}
Fl_Choice {} {
label {Type:} open
xywh {205 100 215 25} down_box BORDER_BOX
} {}
Fl_Button {} {
label {&OK}
xywh {235 135 90 25}
Fl_Tabs {} {open
xywh {10 10 430 165}
} {
Fl_Group {} {
label Basic open
xywh {15 30 415 140}
} {
Fl_Button {} {selected
xywh {20 45 80 75}
}
Fl_Input {} {
label {Name:}
xywh {210 45 215 25}
}
Fl_Input {} {
label {Comment:}
xywh {210 75 215 25}
}
Fl_Input {} {
label {Execute:}
xywh {210 105 185 25}
}
Fl_Button {} {
label {...}
xywh {400 105 25 25}
}
Fl_Choice {} {
label {Type:} open
xywh {210 135 215 25} down_box BORDER_BOX
} {}
}
Fl_Group {} {
label Details open
xywh {15 30 420 140} hide
} {
Fl_Check_Button {} {
label {Run in terminal}
xywh {195 80 235 25} down_box DOWN_BOX
}
Fl_Input {} {
label {Working directory:}
xywh {195 45 205 25}
}
Fl_Button {} {
label {...}
xywh {405 45 25 25}
}
Fl_Check_Button {} {
label {Use startup notification}
xywh {195 110 235 25} down_box DOWN_BOX
}
}
}
Fl_Button {} {
label {&Cancel}
xywh {330 135 90 25}
xywh {350 185 90 25}
}
Fl_Button {} {
label {&OK}
xywh {255 185 90 25}
}
}
}

View File

@ -125,9 +125,17 @@ static void fetch_current_layout(String &current) {
XFree(vd.variant);
}
static int sort_cmp(const void *a, const void *b) {
XkbRF_VarDescPtr first = (XkbRF_VarDescPtr)a;
XkbRF_VarDescPtr second = (XkbRF_VarDescPtr)b;
return strcmp(first->desc, second->desc);
}
static XkbRF_RulesPtr fetch_all_layouts(const String &current) {
char buf[256];
XkbRF_RulesPtr xkb_rules = NULL;
char buf[256];
XkbRF_RulesPtr xkb_rules = NULL;
XkbRF_DescribeVarsPtr layouts = NULL;
/* try to locate rules file */
for(int i = 0; x11_dirs[i]; i++) {
@ -144,13 +152,18 @@ static XkbRF_RulesPtr fetch_all_layouts(const String &current) {
E_WARNING(E_STRLOC ": Unable to load keyboard rules file\n");
return NULL;
}
done:
for(int i = 0; i < xkb_rules->layouts.num_desc; i++) {
snprintf(buf, sizeof(buf), "%s\t%s", xkb_rules->layouts.desc[i].name, xkb_rules->layouts.desc[i].desc);
layouts = &xkb_rules->layouts;
/* sort them */
qsort(layouts->desc, layouts->num_desc, sizeof(XkbRF_VarDescRec), sort_cmp);
for(int i = 0; i < layouts->num_desc; i++) {
snprintf(buf, sizeof(buf), "%s\t%s", layouts->desc[i].name, layouts->desc[i].desc);
layout_browser->add(buf);
if(current == xkb_rules->layouts.desc[i].name) {
if(current == layouts->desc[i].name) {
/* Fl_Browser counts items from 1 */
layout_browser->select(i + 1);
}

View File

@ -1,13 +1,21 @@
/*
* $Id$
*
* ede-launch, launch external application
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2008-2009 EDE Authors.
*
* This program is licensed under terms of the
* GNU General Public License version 2 or newer.
* See COPYING for details.
* Copyright (C) 2012-2014 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
@ -46,7 +54,9 @@
#include <edelib/DesktopFile.h>
#include <edelib/StrUtil.h>
#include <edelib/Debug.h>
#include <edelib/Directory.h>
#include <edelib/Regex.h>
#include <edelib/Util.h>
#include <edelib/Ede.h>
#include "StartupNotify.h"
@ -58,22 +68,40 @@
/* config name where all things are stored and read from */
#define EDE_LAUNCH_CONFIG "ede-launch"
/* default 'Preferred' key in config file */
#define KEY_PREFERRED "Preferred"
/* patterns for guessing user input */
#define REGEX_PATTERN_MAIL "\\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,4}\\b"
#define REGEX_PATTERN_URL "((http|https|ftp|gopher|!file):\\/\\/|www)[a-zA-Z0-9\\-\\._]+\\/?[a-zA-Z0-9_\\.\\-\\?\\+\\/~=&#;,]*[a-zA-Z0-9\\/]{1}"
/* list of known terminals */
static const char *known_terminals[] = {
"xterm",
"rxvt",
"urxvt",
"mrxvt",
"st",
"Terminal",
"gnome-terminal",
"konsole",
0
};
EDELIB_NS_USING_AS(Window, LaunchWindow)
EDELIB_NS_USING_LIST(12, (Resource,
EDELIB_NS_USING_LIST(14, (Resource,
Regex,
String,
list,
DesktopFile,
RES_USER_ONLY,
DESK_FILE_TYPE_APPLICATION,
run_sync, run_async, alert, file_path, window_center_on_screen, str_ends))
run_sync, run_async, alert, file_path, window_center_on_screen, str_ends, system_data_dirs))
static Fl_Pixmap image_run((const char**)run_xpm);
static Fl_Input* dialog_input;
static Fl_Check_Button* in_term;
static Fl_Check_Button *in_term;
static Resource launcher_resource; /* lazy loaded */
static void help(void) {
puts("Usage: ede-launch [OPTIONS] [PROGRAM]");
@ -103,34 +131,28 @@ static int re_match(const char *p, const char *str) {
return re.match(str);
}
static const char *resource_get(Resource &rc, const char *g, const char *k) {
static char buf[64];
static const char *resource_get(const char *g, const char *k) {
if(!launcher_resource)
launcher_resource.load(EDE_LAUNCH_CONFIG);
if(!rc) rc.load(EDE_LAUNCH_CONFIG);
E_RETURN_VAL_IF_FAIL(rc != false, NULL);
E_RETURN_VAL_IF_FAIL(launcher_resource != false, NULL);
if(rc.get(g, k, buf, sizeof(buf)))
return (const char*)buf;
return NULL;
static char buf[128];
return launcher_resource.get(g, k, buf, sizeof(buf)) ? (const char*)buf : NULL;
}
static char* get_basename(const char* path) {
char *p = (char*)strrchr(path, '/');
if(p)
return (p + 1);
return (char*)p;
static char *get_basename(const char* path) {
char *p = (char*)strrchr(path, E_DIR_SEPARATOR);
return p ? p + 1 : p;
}
static char** cmd_split(const char* cmd) {
int sz = 10;
int i = 0;
char* c = strdup(cmd);
static char **cmd_split(const char* cmd) {
int i = 0, sz = 10;
char *c = strdup(cmd);
char** arr = (char**)malloc(sizeof(char*) * sz);
char **arr = (char**)malloc(sizeof(char*) * sz);
for(char* p = strtok(c, " "); p; p = strtok(NULL, " ")) {
for(char *p = strtok(c, " "); p; p = strtok(NULL, " ")) {
if(i >= sz) {
sz *= 2;
arr = (char**)realloc(arr, sizeof(char*) * sz);
@ -165,9 +187,34 @@ static bool allowed_launch_type(const char *t) {
return false;
}
static void start_crasher(const char* cmd, int sig) {
const char* base = get_basename(cmd);
const char* ede_app_flag = "";
#define RETURN_IF_VALID_TERM(t, r) \
do { \
if(t && ((strcmp(t, "linux") != 0) || (strcmp(t, "dumb") != 0))) { \
r = file_path(t, false); \
if(E_UNLIKELY(r.empty())) return true; \
} \
} while(0)
static bool find_terminal(String &ret) {
const char *term = resource_get(KEY_PREFERRED, "terminal");
if(term) {
ret = term;
return true;
}
term = getenv("EDE_LAUNCH_TERMINAL");
RETURN_IF_VALID_TERM(term, ret);
for(int i = 0; known_terminals[i]; i++) {
term = known_terminals[i];
RETURN_IF_VALID_TERM(term, ret);
}
return false;
}
static void start_crasher(const char* cmd, int sig, int pid) {
const char *ede_app_flag = "", *base = get_basename(cmd);
/* this means the app was called without full path */
if(!base) base = cmd;
@ -176,11 +223,11 @@ static void start_crasher(const char* cmd, int sig) {
* determine is our app by checking the prefix; we don't want user to send bug reports about crashes
* of foreign applications
*/
if(strncmp(base, "ede-", 4) == 0)
if((strncmp(base, "ede-", 4) == 0) || (strncmp(base, "edelib-", 7) == 0))
ede_app_flag = "--edeapp";
/* call edelib implementation instead start_child_process() to prevents loops if 'ede-crasher' crashes */
run_sync(PREFIX "/bin/ede-crasher %s --appname %s --apppath %s --signal %i", ede_app_flag, base, cmd, sig);
run_sync(PREFIX "/bin/ede-crasher %s --appname %s --apppath %s --signal %i --pid %i", ede_app_flag, base, cmd, sig, pid);
}
static int start_child_process(const char* cmd) {
@ -258,7 +305,7 @@ static int start_child_process(const char* cmd) {
if(WIFEXITED(status)) {
ret = WEXITSTATUS(status);
} else if(WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
start_crasher(cmd, SIGSEGV);
start_crasher(cmd, SIGSEGV, pid);
} else {
E_WARNING(E_STRLOC ": child '%s' killed\n", cmd);
}
@ -267,6 +314,11 @@ static int start_child_process(const char* cmd) {
}
static int start_child_process_with_core(const char* cmd) {
#ifndef __minix
/*
* Minix does not have setrlimit() so we disable everything as by default it
* will dump core.
*/
struct rlimit r;
errno = 0;
@ -282,25 +334,29 @@ static int start_child_process_with_core(const char* cmd) {
E_WARNING(E_STRLOC ": setrlimit() failed with '%s'\n", strerror(errno));
return -1;
}
#endif
int ret = start_child_process(cmd);
#ifndef __minix
r.rlim_cur = old;
if(setrlimit(RLIMIT_CORE, &r) == -1) {
E_WARNING(E_STRLOC ": setrlimit() failed with '%s'\n", strerror(errno));
return -1;
}
#endif
return ret;
}
static bool start_child(const char* cmd) {
static bool start_child(const char *cmd, bool notify = false) {
E_DEBUG(E_STRLOC ": Starting '%s'\n", cmd);
StartupNotify *n;
if(notify) n = startup_notify_start(cmd, "applications-order");
StartupNotify *n = startup_notify_start(cmd, "applications-order");
int ret = start_child_process_with_core(cmd);
startup_notify_end(n);
if(notify) startup_notify_end(n);
if(ret == 199) {
alert(_("Program '%s' not found.\n\nPlease check if given path to the "
@ -323,29 +379,56 @@ static bool start_child(const char* cmd) {
return true;
}
static bool start_child_in_term(const char *cmd, bool notify = false) {
String term;
if(!find_terminal(term)) {
E_WARNING(E_STRLOC ": unable to find any suitable terminal\n");
return false;
}
/* construct TERM -e cmd */
term += " -e ";
term += cmd;
return start_child(term.c_str(), notify);
}
static bool start_desktop_file(const char *cmd) {
DesktopFile d;
if(!d.load(cmd)) {
alert(_("Unable to load .desktop file '%s'. Got: %s"), cmd, d.strerror());
goto FAIL;
return false;
}
if(d.type() != DESK_FILE_TYPE_APPLICATION) {
alert(_("Starting other types of .desktop files except 'Application' is not supported now"));
goto FAIL;
return false;
}
char buf[PATH_MAX];
if(!d.exec(buf, PATH_MAX)) {
alert(_("Unable to run '%s'.\nProbably this file is malformed or 'Exec' key has non-installed program"), cmd);
goto FAIL;
/*
* Determine working directory and set it first, to reuse buffer. Note that
* it will override working directory path set from command line.
*/
if(d.path(buf, PATH_MAX)) {
errno = 0;
if(chdir(buf) < 0) {
alert(_("Unable to change directory to '%s'. Got '%s' (%i)"), buf, strerror(errno), errno);
}
}
return start_child(buf);
if(!d.exec(buf, PATH_MAX)) {
alert(_("Unable to run '%s'.\nProbably the file is malformed or 'Exec' key has program which is not installed"), cmd);
return false;
}
FAIL:
return false;
bool notify = d.startup_notify();
if(d.terminal())
return start_child_in_term(buf, notify);
return start_child(buf, notify);
}
/* concat all arguments preparing it for start_child() */
@ -398,48 +481,6 @@ static void cancel_cb(Fl_Widget*, void* w) {
win->hide();
}
#define RETURN_IF_VALID_TERM(t, r) \
do { \
if(t && ((strcmp(t, "linux") != 0) || (strcmp(t, "dumb") != 0))) { \
r = file_path(t, false); \
if(E_UNLIKELY(r.empty())) return true; \
} \
} while(0)
static bool find_terminal(String &ret) {
/* before goint to list, try to read it from config file */
Resource rc;
const char *t = resource_get(rc, "Preferred", "terminal");
if(t) {
ret = t;
return true;
}
/* list of known terminals */
static const char *terms[] = {
"xterm",
"rxvt",
"Terminal",
"gnome-terminal",
"konsole",
0
};
const char* term = getenv("TERM");
RETURN_IF_VALID_TERM(term, ret);
term = getenv("COLORTERM");
RETURN_IF_VALID_TERM(term, ret);
for(int i = 0; terms[i]; i++) {
term = terms[i];
RETURN_IF_VALID_TERM(term, ret);
}
return false;
}
static void ok_cb(Fl_Widget*, void* w) {
LaunchWindow* win = (LaunchWindow*)w;
const char* cmd = dialog_input->value();
@ -451,19 +492,7 @@ static void ok_cb(Fl_Widget*, void* w) {
Fl::check();
/* TODO: is 'cmd' safe after hide? */
if(in_term->value()) {
char buf[128];
String term;
if(find_terminal(term)) {
snprintf(buf, sizeof(buf), "%s -e %s", term.c_str(), cmd);
started = start_child(buf);
} else {
E_WARNING(E_STRLOC ": unable to find any suitable terminal\n");
}
} else {
started = start_child(cmd);
}
started = (in_term->value()) ? start_child_in_term(cmd) : start_child(cmd);
if(!started) {
/* show dialog again */
@ -473,6 +502,7 @@ static void ok_cb(Fl_Widget*, void* w) {
dialog_input->position(0, dialog_input->size());
} else {
Resource rc;
/* so could load previous content */
rc.load(EDE_LAUNCH_CONFIG);
rc.set("History", "open", cmd);
@ -491,12 +521,9 @@ static int start_dialog(int argc, char** argv) {
dialog_input = new Fl_Input(70, 90, 290, 25, _("Open:"));
Resource rc;
char buf[128];
if(rc.load(EDE_LAUNCH_CONFIG) && rc.get("History", "open", buf, sizeof(buf))) {
dialog_input->value(buf);
const char *cmd = resource_get("History", "open");
if(cmd) {
dialog_input->value(cmd);
/* make text appear selected */
dialog_input->position(0, dialog_input->size());
}
@ -597,19 +624,18 @@ int main(int argc, char** argv) {
return 1;
}
}
/* check if we have .desktop file */
if(argv[ca] && str_ends(argv[ca], ".desktop"))
return RETURN_FROM_BOOL(start_desktop_file(argv[ca]));
/* make arguments and exec program */
String args;
Resource rc;
const char *prog = NULL;
if(launch_type) {
/* explicitly launch what user requested */
prog = resource_get(rc, "Preferred", launch_type);
prog = resource_get(KEY_PREFERRED, launch_type);
if(!prog) {
E_WARNING(E_STRLOC ": Unable to find out launch type\n");
@ -625,7 +651,7 @@ int main(int argc, char** argv) {
* Note however how this matching works on only one argument; other would be ignored
*/
if(re_match(REGEX_PATTERN_MAIL, argv[ca]) > 0) {
prog = resource_get(rc, "Preferred", "mail");
prog = resource_get(KEY_PREFERRED, "mail");
if(!prog) {
E_WARNING(E_STRLOC ": Unable to find mail agent\n");
return 1;
@ -636,7 +662,7 @@ int main(int argc, char** argv) {
/* use only one argumet */
argc = ca + 1;
} else if(re_match(REGEX_PATTERN_URL, argv[ca]) > 0) {
prog = resource_get(rc, "Preferred", "browser");
prog = resource_get(KEY_PREFERRED, "browser");
if(!prog) {
E_WARNING(E_STRLOC ": Unable to find browser\n");
return 1;

View File

@ -13,7 +13,7 @@ SubDir TOP ede-notify-daemon ;
SOURCE = ede-notify-daemon.cpp NotifyWindow.cpp ;
EdeProgram ede-notify-daemon : $(SOURCE) ;
LinkAgainst ede-notify-daemon : $(EDELIB_DBUS_LIB) ;
LinkAgainst ede-notify-daemon : $(EDELIB_DBUS_LIB) $(PTHREAD_LIBS) ;
TranslationStrings locale : $(SOURCE) ;

View File

@ -1,3 +1,23 @@
/*
* $Id: ede-panel.cpp 3330 2012-05-28 10:57:50Z karijes $
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <FL/Fl.H>
#include <FL/x.H>
#include <FL/fl_draw.H>
@ -31,6 +51,8 @@ static void timeout_cb(void *w) {
NotifyWindow::NotifyWindow() : Fl_Window(DEFAULT_W, DEFAULT_H) {
FL_NORMAL_SIZE = 12;
timer_set = 0;
type(NOTIFYWINDOW_TYPE);
color(FL_BACKGROUND2_COLOR);
box(FL_BORDER_BOX);
@ -67,6 +89,24 @@ NotifyWindow::NotifyWindow() : Fl_Window(DEFAULT_W, DEFAULT_H) {
border(0);
}
void NotifyWindow::add_timeout(void) {
E_DEBUG(E_STRLOC ": adding timer\n");
if(timer_set) return;
if(exp == -1) exp = DEFAULT_EXPIRE;
Fl::add_timeout((double)exp / (double)1000, timeout_cb, this);
timer_set = 1;
}
void NotifyWindow::remove_timeout(void) {
E_DEBUG(E_STRLOC ": removing timer\n");
if(!timer_set) return;
Fl::remove_timeout(timeout_cb);
timer_set = 0;
}
void NotifyWindow::set_icon(const char *img) {
E_RETURN_IF_FAIL(IconLoader::inited());
E_RETURN_IF_FAIL(img != NULL);
@ -75,17 +115,17 @@ void NotifyWindow::set_icon(const char *img) {
}
void NotifyWindow::set_body(const char *s) {
summary->resize(summary->x(), summary->y() - (summary->h() / 2), summary->w(), summary->h());
summary->resize(65, 10, 185, 25);
//summary->resize(summary->x(), summary->y() - (summary->h() / 2), summary->w(), summary->h());
body->value(s);
body->show();
}
void NotifyWindow::show(void) {
if(exp != 0) {
if(exp == -1) exp = DEFAULT_EXPIRE;
Fl::add_timeout((double)exp / (double)1000, timeout_cb, this);
}
/* the case when timer should not be added */
if(exp != 0)
add_timeout();
Fl_Window::show();
netwm_window_set_type(fl_xid(this), NETWM_WINDOW_TYPE_NOTIFICATION);
@ -98,7 +138,7 @@ void NotifyWindow::resize(int X, int Y, int W, int H) {
* do not call further if window is shown: different strategy is needed as every time
* window is re-configured, this will be called
*/
if(shown()) return;
//if(shown()) return;
/* resize summary if needed */
if(summary->size() > 0) {
@ -161,3 +201,17 @@ void NotifyWindow::resize(int X, int Y, int W, int H) {
Fl_Window::resize(X, Y, W, H);
}
int NotifyWindow::handle(int event) {
switch(event) {
case FL_ENTER:
remove_timeout();
goto done;
case FL_LEAVE:
add_timeout();
goto done;
}
done:
return Fl_Window::handle(event);
}

View File

@ -1,3 +1,23 @@
/*
* $Id: ede-panel.cpp 3330 2012-05-28 10:57:50Z karijes $
*
* Copyright (C) 2012-2014 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __NOTIFYWINDOW_H__
#define __NOTIFYWINDOW_H__
@ -11,16 +31,19 @@
class NotifyWindow : public Fl_Window {
private:
int id, exp;
unsigned int id;
int exp, timer_set;
Fl_Button *closeb;
Fl_Box *imgbox;
Fl_Multiline_Output *summary, *body;
void add_timeout(void);
void remove_timeout(void);
public:
NotifyWindow();
void set_id(int i) { id = i; }
int get_id(void) { return id; }
void set_id(unsigned int i) { id = i; }
unsigned int get_id(void) { return id; }
void set_icon(const char *img);
void set_summary(const char *s) { summary->value(s); }
@ -30,10 +53,18 @@ public:
* match to spec: if is -1, then we handle it, if is 0, then window will not be closed and
* the rest is sender specific
*/
void set_expire(int t) { exp = t; }
void set_expire(int t, bool update_timer) {
exp = t;
// if(update_timer) {
// remove_timeout();
// add_timeout();
// }
}
void show(void);
virtual void resize(int X, int Y, int W, int H);
virtual int handle(int event);
};
#endif

View File

@ -1,3 +1,23 @@
/*
* $Id: ede-panel.cpp 3330 2012-05-28 10:57:50Z karijes $
*
* Copyright (C) 2012-2014 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@ -6,11 +26,13 @@
#include <string.h>
#include <limits.h>
#include <edelib/Ede.h>
#include <edelib/Debug.h>
#ifdef EDELIB_HAVE_DBUS
#include <FL/Fl.H>
#include <FL/Fl_Shared_Image.H>
#include <edelib/Ede.h>
#include <edelib/Debug.h>
#include <edelib/EdbusConnection.h>
#include <edelib/EdbusMessage.h>
#include <edelib/EdbusData.h>
@ -25,7 +47,7 @@
/* server info sent via GetServerInformation */
#define EDE_NOTIFY_DAEMON_NAME "EDE Notification Daemon"
#define EDE_NOTIFY_DAEMON_VENDOR "ede"
#define EDE_NOTIFY_DAEMON_VERSION "0.1"
#define EDE_NOTIFY_DAEMON_VERSION "0.2"
#define EDE_NOTIFY_DAEMON_SPEC_VERSION "1.2"
#define NOTIFICATIONS_DBUS_PATH "/org/freedesktop/Notifications"
@ -43,7 +65,6 @@
#define WINDOWS_PADDING 10
#define IS_MEMBER(m, s1) (strcmp((m->member()), (s1)) == 0)
#define CHECK_ARGV(argv, pshort, plong) ((strcmp(argv, pshort) == 0) || (strcmp(argv, plong) == 0))
EDELIB_NS_USING(EdbusConnection)
EDELIB_NS_USING(EdbusMessage)
@ -62,7 +83,8 @@ static bool server_running;
* list of server capabilities
* check all available on: http://people.gnome.org/~mccann/docs/notification-spec/notification-spec-latest.html
*/
static const char *server_caps[] = {"actions", "body", "icon-static", 0};
// static const char *server_caps[] = {"actions", "body", "icon-static", 0};
static const char *server_caps[] = {"body", "icon-static", 0};
/* increased every time new notification window is shown; must be less than UINT_MAX */
static unsigned int notify_id;
@ -107,22 +129,40 @@ static bool get_int_coordinate(const char *n, EdbusDict &hints, int &c) {
return true;
}
static void show_window(unsigned int id,
const char *app_name,
const char *app_icon,
const char *summary,
const char *body,
int expire_timeout,
EdbusDict &hints)
static void show_or_update_window(bool update_only,
unsigned int id,
const char *app_name,
const char *app_icon,
const char *summary,
const char *body,
int expire_timeout,
EdbusDict &hints)
{
byte_t u = get_urgency_level(hints);
NotifyWindow *win = NULL;
NotifyWindow *win = new NotifyWindow();
if(update_only) {
E_DEBUG(E_STRLOC ": Requesting update\n");
/* try to find existing window with given id */
Fl_Window *wi;
NotifyWindow *tmp;
if(!empty_str(summary))
win->set_summary(summary);
if(!empty_str(body))
win->set_body(body);
for(wi = Fl::first_window(); wi; wi = Fl::next_window(wi)) {
if(wi->type() != NOTIFYWINDOW_TYPE) continue;
tmp = (NotifyWindow*)wi;
if(tmp->get_id() == id) {
E_DEBUG(E_STRLOC ": Requesting update - win found\n");
win = tmp;
break;
}
}
}
/* window not found or new window requested */
if(!win) win = new NotifyWindow();
if(!empty_str(summary)) win->set_summary(summary);
if(!empty_str(body)) win->set_body(body);
if(empty_str(app_icon)) {
switch(u) {
case URGENCY_CRITICAL:
@ -137,7 +177,7 @@ static void show_window(unsigned int id,
win->set_icon(app_icon);
win->set_id(id);
win->set_expire(expire_timeout);
win->set_expire(expire_timeout, update_only);
/* according to spec, both coordinates must exist so window can be positioned as desired */
int X, Y;
@ -155,11 +195,11 @@ static void show_window(unsigned int id,
px = sw - WINDOWS_PADDING - win->w();
py = sh - WINDOWS_PADDING - win->h();
Fl::lock();
/*
* iterate through shown windows and find position where to put our one
* FIXME: this is quite primitive window position deducing facility
*
* TODO: add locking here
*/
Fl_Window *wi;
for(wi = Fl::first_window(); wi; wi = Fl::next_window(wi)) {
@ -173,12 +213,12 @@ static void show_window(unsigned int id,
}
}
Fl::unlock();
win->position(px, py);
}
/* we are already running loop, so window will handle events */
win->show();
if(!win->shown())
win->show();
}
static int handle_notify(EdbusConnection *dbus, const EdbusMessage *m) {
@ -189,7 +229,7 @@ static int handle_notify(EdbusConnection *dbus, const EdbusMessage *m) {
const char *app_name, *app_icon, *summary, *body;
app_name = app_icon = summary = body = NULL;
unsigned int replaces_id;
unsigned int replaces_id, id;
int expire_timeout;
EdbusMessage::const_iterator it = m->begin();
@ -226,19 +266,33 @@ static int handle_notify(EdbusConnection *dbus, const EdbusMessage *m) {
E_RETURN_VAL_IF_FAIL(it->is_int32(), 0);
expire_timeout = it->to_int32();
/* specification dumb stuff: what if we got UINT_MAX?? here we will reverse to first ID */
if(++notify_id == UINT_MAX) notify_id = 1;
if(replaces_id) {
//replaces_id == notify_id;
if(replaces_id > 0) {
id = replaces_id;
} else {
show_window(notify_id, app_name, app_icon, summary, body, expire_timeout, hints);
/* by the spec, if we got MAX, reversing will be just fine */
if(++notify_id == UINT_MAX) notify_id = 1;
id = notify_id;
}
/* reply sent to client */
/* this should never happen */
E_RETURN_VAL_IF_FAIL(id != 0, 0);
show_or_update_window(replaces_id > 0, id,
app_name, app_icon, summary, body, expire_timeout, hints);
#if 0
if(replaces_id) {
update_window(replaces_id, app_name, app_icon, summary, body, expire_timeout, hints);
sent_id = replaces_id;
} else {
show_window(notify_id, app_name, app_icon, summary, body, expire_timeout, hints);
sent_id = notify_id;
}
#endif
/* reply sent to client, with used window id */
EdbusMessage reply;
reply.create_reply(*m);
reply << EdbusData::from_uint32(replaces_id);
reply << EdbusData::from_uint32(id);
dbus->send(reply);
return 1;
@ -279,6 +333,8 @@ static int notifications_dbus_method_cb(const EdbusMessage *m, void *d) {
return 1;
}
#endif /* EDELIB_HAVE_DBUS */
#if 0
static int notifications_dbus_signal_cb(const EdbusMessage *m, void *d) {
E_DEBUG("+=> %s\n", m->member());
@ -294,6 +350,8 @@ static void help(void) {
puts(" -n, --no-daemon do not run in background");
}
#define CHECK_ARGV(argv, pshort, plong) ((strcmp(argv, pshort) == 0) || (strcmp(argv, plong) == 0))
int main(int argc, char **argv) {
/* daemon behaves as GUI app, as will use icon theme and etc. */
EDE_APPLICATION("ede-notify-daemon");
@ -310,6 +368,7 @@ int main(int argc, char **argv) {
}
}
#ifdef EDELIB_HAVE_DBUS
server_running = false;
notify_id = 0;
EdbusConnection dbus;
@ -332,7 +391,6 @@ int main(int argc, char **argv) {
dbus.register_object(NOTIFICATIONS_DBUS_PATH);
dbus.method_callback(notifications_dbus_method_cb, &dbus);
//dbus.signal_callback(notifications_dbus_signal_cb, &dbus);
dbus.setup_listener_with_fltk();
server_running = true;
@ -340,5 +398,8 @@ int main(int argc, char **argv) {
Fl::wait(FOREVER);
IconLoader::shutdown();
#else
E_WARNING(E_STRLOC ": edelib is compiled without DBus so notification daemon is not able to receive notification messages\n");
#endif
return 0;
}

View File

@ -3,8 +3,64 @@
N_EVENTS=5
notify_cmd="notify-send --expire-time=10000"
#notify_cmd="notify-send --expire-time=3000"
#
#for((i=0;i<$N_EVENTS;i++)) do
# $notify_cmd "title $i" "this is content"
#done
for((i=0;i<$N_EVENTS;i++)) do
$notify_cmd "title $i" "this is content"
done
#method call sender=:1.798 -> dest=org.freedesktop.Notifications serial=116 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
# string "Mumble"
# uint32 1
# string "gtk-dialog-info"
# string "User Joined Channel"
# string "<a href='clientid://df93eabe004245bd18dd38cf9a07bd5242b2f522' class='log-user log-target'>madamova</a> entered channel."
# array [
# ]
# array [
# dict entry(
# string "desktop-entry"
# variant string "mumble"
# )
# ]
# int32 -1
dbus-send --type=method_call \
--dest=org.freedesktop.Notifications \
/org/freedesktop/Notifications org.freedesktop.Notifications.Notify \
string:"Mumble" \
uint32:1 \
string:"gtk-dialog-info" \
string:"User Joined Channel" \
string:"<a href='clientid://df93eabe004245bd18dd38cf9a07bd5242b2f522' class='log-user log-target'>madamova</a> entered channel." \
array:string:'' \
dict:string:string:'','' \
int32:-1
sleep 1
dbus-send --type=method_call \
--dest=org.freedesktop.Notifications \
/org/freedesktop/Notifications org.freedesktop.Notifications.Notify \
string:"Mumble 2" \
uint32:1 \
string:"gtk-dialog-info" \
string:"User Joined Channel #2" \
string:"<a href='clientid://df93eabe004245bd18dd38cf9a07bd5242b2f522' class='log-user log-target'>madamova</a> entered channel. asdasd asdasdsa asdasd asdasd asdasdsa" \
array:string:'' \
dict:string:string:'','' \
int32:-1
sleep 1
dbus-send --type=method_call \
--dest=org.freedesktop.Notifications \
/org/freedesktop/Notifications org.freedesktop.Notifications.Notify \
string:"Mumble 2" \
uint32:1 \
string:"gtk-dialog-info" \
string:"User Joined Channel #2 dasdasd asdasfdsa fsdfsdfa sdfsdfasdf asdfsdfasdfasdfasdfa asdfasdfdsafasdfasdfdsafdsaf sadfsdafds" \
string:"doh!" \
array:string:'' \
dict:string:string:'','' \
int32:-1

View File

@ -1,10 +1,41 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __APPLET_H__
#define __APPLET_H__
#define EDE_PANEL_APPLET_INTERFACE_VERSION 0x01
#include <edelib/Resource.h>
EDELIB_NS_USING_AS(Resource, PanelResource)
class Fl_Widget;
/* stored version in each applet shared library in case interface get changed */
#define EDE_PANEL_APPLET_INTERFACE_VERSION 0x01
/* random number (must be less than FL_WINDOW) so panel could know it is AppletWidget<> */
#define EDE_PANEL_APPLET_TYPE 0x27
/*
* Options assigned to each applet: how it will be resizable (horizontally or vertically)
* and how it will be aligned. Each applet is by default aligned left without resizing ability.
*/
enum {
EDE_PANEL_APPLET_OPTION_RESIZABLE_H = (1 << 1),
EDE_PANEL_APPLET_OPTION_RESIZABLE_V = (1 << 2),
@ -12,6 +43,26 @@ enum {
EDE_PANEL_APPLET_OPTION_ALIGN_RIGHT = (1 << 4)
};
/*
* each applet want to inherit this class if would like to exchange data with panel
* NOTE: new things could be added in future, but that will be reflected through EDE_PANEL_APPLET_INTERFACE_VERSION
*/
template <typename T>
class AppletWidget : public T {
public:
AppletWidget(int X, int Y, int W, int H, const char *l = 0) : T(X, Y, W, H, l) {
T::type(EDE_PANEL_APPLET_TYPE);
}
virtual ~AppletWidget() { }
/*
* Override this method to access panel configuration. Note that 'PanelResource' object
* will be destroyed after applets are loaded, so do not hold reference to this address.
*/
virtual void configure(PanelResource *conf) { }
};
struct AppletInfo {
const char *name;
const char *klass_name;
@ -21,6 +72,7 @@ struct AppletInfo {
unsigned long options;
};
/* module stuff */
typedef Fl_Widget* (*applet_create_t)(void);
typedef void (*applet_destroy_t)(Fl_Widget *);
@ -29,11 +81,13 @@ typedef void (*applet_destroy_info_t)(AppletInfo *a);
typedef float (*applet_version_t)(void);
/* the main macro each applet library must implement */
/*
* The main macro each applet library must implement. It will assign apropriate values
* so applet loader can use them to load applet class with some common metadata.
*/
#define EDE_PANEL_APPLET_EXPORT(klass, aoptions, aname, aversion, aicon, aauthor) \
extern "C" Fl_Widget *ede_panel_applet_create(void) { \
return new klass; \
return new klass; \
} \
\
extern "C" void ede_panel_applet_destroy(Fl_Widget *w) { \

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <dlfcn.h>
#include <string.h>
#include <edelib/Debug.h>
@ -13,10 +33,10 @@ struct AppletData {
Fl_Widget *awidget; /* widget from the applet */
AppletInfo *ainfo; /* applet informations */
applet_create_t create_func;
applet_destroy_t destroy_func;
applet_create_t create_func;
applet_destroy_t destroy_func;
applet_destroy_info_t destroy_info_func;
applet_destroy_info_t destroy_info_func;
};
static void clear_applet(AppletData *a) {
@ -35,10 +55,6 @@ static void clear_applet(AppletData *a) {
delete a;
}
AppletManager::~AppletManager() {
clear();
}
bool AppletManager::load(const char *path) {
dlerror();
const char *dl_err = NULL;
@ -46,7 +62,7 @@ bool AppletManager::load(const char *path) {
void *a = dlopen(path, RTLD_LAZY);
if(!a) {
dl_err = dlerror();
E_WARNING(E_STRLOC ": Unable to load '%s' : '%s'\n", path, dl_err);
E_WARNING(E_STRLOC ": Unable to load '%s': '%s'\n", path, dl_err);
return false;
}
@ -92,7 +108,6 @@ bool AppletManager::load(const char *path) {
return false;
}
AppletData *data = new AppletData;
data->dl = a;
data->awidget = NULL;
@ -111,12 +126,12 @@ bool AppletManager::load(const char *path) {
return true;
}
void AppletManager::clear(void) {
if(applet_list.empty())
return;
void AppletManager::clear(Panel *p) {
E_RETURN_IF_FAIL(applet_list.size() > 0);
AListIter it = applet_list.begin(), it_end = applet_list.end();
while(it != it_end) {
AListIter it = applet_list.begin(), ite = applet_list.end();
while(it != ite) {
p->remove((*it)->awidget);
clear_applet(*it);
it = applet_list.erase(it);
}
@ -126,30 +141,39 @@ void AppletManager::clear(void) {
* Must be called so widget can actually be added to FLTK parent. Widgets will be created and
* added to the group.
*/
void AppletManager::fill_group(Panel *p) {
AListIter it = applet_list.begin(), it_end = applet_list.end();
void AppletManager::fill_group(Panel *p, PanelResource *res) {
AListIter it = applet_list.begin(), ite = applet_list.end();
AppletData *applet;
for(; it != it_end; ++it) {
for(; it != ite; ++it) {
applet = *it;
/* allocate memory for widget and append it to group */
/* allocate memory for widget and append it to the group */
applet->awidget = applet->create_func();
/* call configuration function if needed */
if(res && applet->awidget->type() == EDE_PANEL_APPLET_TYPE) {
/* a hackery to make compiler happy */
typedef AppletWidget<Fl_Widget> AW;
AW *tmp = (AW*)(applet->awidget);
tmp->configure(res);
}
p->add(applet->awidget);
}
}
void AppletManager::unfill_group(Panel *p) {
AListIter it = applet_list.begin(), it_end = applet_list.end();
AListIter it = applet_list.begin(), ite = applet_list.end();
for(; it != it_end; ++it)
for(; it != ite; ++it)
p->remove((*it)->awidget);
}
bool AppletManager::get_applet_options(Fl_Widget *o, unsigned long &opts) {
AListIter it = applet_list.begin(), it_end = applet_list.end();
AListIter it = applet_list.begin(), ite = applet_list.end();
for(; it != it_end; ++it) {
for(; it != ite; ++it) {
if(o == (*it)->awidget) {
opts = (*it)->ainfo->options;
return true;

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __APPLETMANAGER_H__
#define __APPLETMANAGER_H__
@ -9,17 +29,16 @@ class Panel;
class Fl_Widget;
struct AppletData;
typedef edelib::list<AppletData*> AList;
typedef edelib::list<AppletData*>::iterator AListIter;
typedef EDELIB_NS_PREPEND(list<AppletData*>) AList;
typedef EDELIB_NS_PREPEND(list<AppletData*>::iterator) AListIter;
class AppletManager {
private:
AList applet_list;
public:
~AppletManager();
bool load(const char *path);
void clear(void);
void fill_group(Panel *p);
void clear(Panel *p);
void fill_group(Panel *p, PanelResource *res);
void unfill_group(Panel *p);
bool get_applet_options(Fl_Widget *o, unsigned long &opts);

View File

@ -1,49 +1,41 @@
#include "Applet.h"
#include "Panel.h"
/*
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <unistd.h>
#include <FL/Fl_Button.H>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/x.H>
#include <edelib/Nls.h>
#include <edelib/Debug.h>
#include <FL/x.H>
#include "Hider.h"
#include "Panel.h"
/* delay in secs */
#define PANEL_MOVE_DELAY 0.0015
/* how fast we will move X axis */
#define PANEL_ANIM_SPEED 50
static void hide_cb(Fl_Widget*, void *h);
class Hider : public Fl_Button {
private:
int old_x, old_y, is_hidden, old_px, stop_x;
public:
Hider() : Fl_Button(0, 0, 10, 25, "@>"), old_x(0), old_y(0), is_hidden(0), old_px(0), stop_x(0) {
labelsize(8);
box(FL_FLAT_BOX);
tooltip(_("Hide panel"));
callback(hide_cb, this);
}
int panel_hidden(void) { return is_hidden; }
void panel_hidden(int s) { is_hidden = s; }
void panel_show(void);
void panel_hide(void);
void post_show(void);
void post_hide(void);
void animate(void);
};
static void hide_cb(Fl_Widget*, void *h) {
Hider *hh = (Hider*)h;
if(hh->panel_hidden())
hh->panel_show();
else
hh->panel_hide();
hh->panel_hidden() ? hh->panel_show() : hh->panel_hide();
}
static void animate_cb(void *h) {
@ -51,8 +43,15 @@ static void animate_cb(void *h) {
hh->animate();
}
Hider::Hider() : Fl_Button(0, 0, 10, 25, "@>"), old_x(0), old_y(0), is_hidden(0), old_px(0), stop_x(0) {
labelsize(8);
box(FL_FLAT_BOX);
tooltip(_("Hide panel"));
callback(hide_cb, this);
}
void Hider::animate(void) {
Panel *p = EDE_PANEL_GET_PANEL_OBJECT(this);
Panel *p = (Panel*)parent();
if(!panel_hidden()) {
/* hide */
@ -76,7 +75,8 @@ void Hider::animate(void) {
}
void Hider::panel_hide(void) {
Panel *p = EDE_PANEL_GET_PANEL_OBJECT(this);
Panel *p = (Panel*)parent();
int X, Y, W, H;
p->screen_size(X, Y, W, H);
@ -87,7 +87,7 @@ void Hider::panel_hide(void) {
}
void Hider::post_hide(void) {
Panel *p = EDE_PANEL_GET_PANEL_OBJECT(this);
Panel *p = (Panel*)parent();
/* align to bounds */
p->position(stop_x, p->y());
@ -116,7 +116,7 @@ void Hider::panel_show(void) {
}
void Hider::post_show(void) {
Panel *p = EDE_PANEL_GET_PANEL_OBJECT(this);
Panel *p = (Panel*)parent();
/* align to bounds */
p->position(old_px, p->y());
@ -136,12 +136,3 @@ void Hider::post_show(void) {
panel_hidden(0);
tooltip(_("Hide panel"));
}
EDE_PANEL_APPLET_EXPORT (
Hider,
EDE_PANEL_APPLET_OPTION_ALIGN_RIGHT,
"Hide-panel applet",
"0.1",
"empty",
"Sanel Zukan"
)

41
ede-panel/Hider.h Normal file
View File

@ -0,0 +1,41 @@
/*
* $Id: ede-panel.cpp 3463 2012-12-17 15:49:33Z karijes $
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <FL/Fl_Button.H>
#ifndef __HIDER_H__
#define __HIDER_H__
class Hider : public Fl_Button {
private:
int old_x, old_y, is_hidden, old_px, stop_x;
public:
Hider();
int panel_hidden(void) { return is_hidden; }
void panel_hidden(int s) { is_hidden = s; }
void panel_show(void);
void panel_hide(void);
void post_show(void);
void post_hide(void);
void animate(void);
};
#endif

View File

@ -10,7 +10,8 @@
SubDir TOP ede-panel ;
EdeProgram ede-panel : Panel.cpp AppletManager.cpp ede-panel.cpp ;
EdeProgram ede-panel : Hider.cpp Panel.cpp AppletManager.cpp ede-panel.cpp ;
LinkAgainst ede-panel : -ldl ;
#ObjectC++Flags Panel.cpp : -DEDE_PANEL_LOCAL_APPLETS ;
if $(OS) != "SOLARIS" {
@ -30,13 +31,13 @@ rule PanelApplet
}
# append default extension
target = $(<:S=$(SUFLIB_SHARED)) ;
target = $(1:S=$(SUFLIB_SHARED)) ;
Main $(target) : $(>) ;
ObjectC++Flags $(>) : $(GLOBALFLAGS) -fPIC $(FLTKINCLUDE) -I [ FDirName $(TOP) ede-panel ] $(EDELIBINCLUDE) ;
Main $(target) : $(2) ;
ObjectC++Flags $(2) : $(GLOBALFLAGS) -fPIC $(FLTKINCLUDE) -I [ FDirName $(TOP) ede-panel ] $(EDELIBINCLUDE) ;
LinkAgainst $(target) : $(3) $(EDELIBLIB) $(EDELIB_GUI_LIB) $(FLTKLIB) $(STDLIB) ;
LINKFLAGS on $(target) = $(linker_stuff) [ on $(target) return $(LINKFLAGS) ] ;
LINKFLAGS on $(target) = $(linker_stuff) [ on $(target) return $(LINKFLAGS) ] $(3) ;
InstallProgram $(EDE_PANEL_APPLETS_DIR) : $(target) ;

View File

@ -1,17 +1,40 @@
/*
* $Id$
*
* Copyright (C) 2012-2014 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <FL/x.H>
#include <X11/Xproto.h>
#include <edelib/Debug.h>
#include <edelib/List.h>
#include <edelib/WindowXid.h>
#include <edelib/Resource.h>
#include <edelib/Util.h>
#include <edelib/Netwm.h>
#include <edelib/Directory.h>
#include <edelib/StrUtil.h>
#include "Panel.h"
#include "Hider.h"
/* empty space from left and right panel border */
#define INITIAL_SPACING 5
@ -22,25 +45,30 @@
/* default panel height */
#define DEFAULT_PANEL_H 35
#define APPLET_EXTENSION ".so"
#undef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#undef MAX
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
EDELIB_NS_USING_LIST(10, (list,
Resource,
String,
window_xid_create,
build_filename,
str_trim,
netwm_window_set_strut,
netwm_window_remove_strut,
netwm_window_set_type,
netwm_workarea_get_size,
NETWM_WINDOW_TYPE_DOCK))
NETWM_WINDOW_TYPE_DOCK))
typedef list<Fl_Widget*> WidgetList;
typedef list<Fl_Widget*>::iterator WidgetListIt;
/* used only insid x_events */
static Panel *gpanel;
inline bool intersects(Fl_Widget *o1, Fl_Widget *o2) {
return (MAX(o1->x(), o2->x()) <= MIN(o1->x() + o1->w(), o2->x() + o2->w()) &&
MAX(o1->y(), o2->y()) <= MIN(o1->y() + o1->h(), o2->y() + o2->h()));
@ -50,14 +78,14 @@ static int xerror_handler(Display *d, XErrorEvent *e) {
if(e->request_code == X_GetImage)
return 0;
char buf[128];
/* keep it static as no multiple panels will be run */
static char buf[128];
/*
* construct the similar message format like X11 is using by default, but again, little
* bit different so we knows it comes from here
*/
sprintf(buf, "%d", e->request_code);
snprintf(buf, sizeof(buf), "%d", e->request_code);
XGetErrorDatabaseText(d, "XRequest", buf, "%d", buf, sizeof(buf));
fprintf(stderr, "%s: ", buf);
@ -77,20 +105,39 @@ static void make_me_dock(Fl_Window *win) {
netwm_window_set_type(fl_xid(win), NETWM_WINDOW_TYPE_DOCK);
}
static int x_events(int ev) {
/*
* This is quite stupid to do, but hopefully very reliable. When screen is resized
* root window was resized too and using those sizes, panel is placed. Tracking workarea changes
* isn't much of use, as setting struts dimensions will affect workarea dimension too.
*/
if(fl_xevent->type == ConfigureNotify &&
(fl_xevent->xconfigure.window == RootWindow(fl_display, fl_screen))) {
gpanel->update_size_and_pos(false, false,
fl_xevent->xconfigure.x,
fl_xevent->xconfigure.y,
fl_xevent->xconfigure.width,
fl_xevent->xconfigure.height);
}
/* let others receive the same event */
return 0;
}
/* horizontaly centers widget in the panel */
static void center_widget_h(Fl_Widget *o, Panel *self) {
int ph, wy;
static void fix_widget_h(Fl_Widget *o, Panel *self) {
int ph, wy, H = self->h() - 10;
ph = self->panel_h() / 2;
wy = ph - (o->h() / 2);
o->position(o->x(), wy);
wy = ph - (H / 2);
o->resize(o->x(), wy, o->w(), H);
}
static void add_from_list(WidgetList &lst, Panel *self, int &X, bool inc) {
WidgetListIt it = lst.begin(), it_end = lst.end();
WidgetListIt it = lst.begin(), ite = lst.end();
Fl_Widget *o;
while(it != it_end) {
while(it != ite) {
o = *it;
/* 'inc == false' means we are going from right to left */
@ -174,14 +221,17 @@ static void move_widget(Panel *self, Fl_Widget *o, int &sx, int &sy) {
}
#endif
Panel::Panel() : PanelWindow(300, 30) {
Panel::Panel() : PanelWindow(300, 30, "ede-panel") {
gpanel = this;
hider = NULL;
clicked = 0;
sx = sy = 0;
vpos = PANEL_POSITION_BOTTOM;
screen_x = screen_y = screen_w = screen_h = screen_h_half = 0;
width_perc = 100;
can_move_widgets = false;
can_drag = true;
can_drag = false;
box(FL_UP_BOX);
read_config();
@ -189,8 +239,7 @@ Panel::Panel() : PanelWindow(300, 30) {
void Panel::read_config(void) {
Resource r;
if(!r.load("ede-panel"))
return;
r.load("ede-panel");
int tmp;
if(r.get("Panel", "position", tmp, PANEL_POSITION_BOTTOM)) {
@ -205,6 +254,26 @@ void Panel::read_config(void) {
width_perc = tmp;
}
/* small button on the right edge for panel sliding */
r.get("Panel", "hider", tmp, 1);
if(tmp) {
if(!hider) {
hider = new Hider();
add(hider);
}
/* in case was hidden before */
hider->show();
} else {
if(hider) hider->hide();
}
char buf[128];
if(r.get("Panel", "applets", buf, sizeof(buf)))
load_applets(buf, &r);
else
load_applets(0, &r);
}
void Panel::save_config(void) {
@ -217,7 +286,7 @@ void Panel::save_config(void) {
}
void Panel::do_layout(void) {
E_RETURN_IF_FAIL(mgr.napplets() > 0);
E_RETURN_IF_FAIL(children() > 0);
Fl_Widget *o;
unsigned long opts;
@ -229,8 +298,14 @@ void Panel::do_layout(void) {
for(int i = 0; i < children(); i++) {
o = child(i);
/* first center it vertically */
center_widget_h(o, this);
/* first resize it to some reasonable height and center it vertically */
fix_widget_h(o, this);
/* manage hider specifically */
if(hider && o == hider) {
right.push_back(o);
continue;
}
/* could be slow, but I'm relaying how number of loaded applets will not be that large */
if(!mgr.get_applet_options(o, opts)) {
@ -297,11 +372,11 @@ void Panel::do_layout(void) {
* since add_from_list() will already reserve some space by current child width and default spacing,
* those values will be used again or holes will be made
*/
WidgetListIt it = resizable_h.begin(), it_end = resizable_h.end();
WidgetListIt it = resizable_h.begin(), ite = resizable_h.end();
o = resizable_h.front();
X = o->x();
while(it != it_end) {
while(it != ite) {
o = *it;
W = o->w() + free_w;
@ -312,26 +387,63 @@ void Panel::do_layout(void) {
}
}
void Panel::set_strut(short state) {
if(state & PANEL_STRUT_REMOVE)
netwm_window_remove_strut(fl_xid(this));
/* no other flags */
if(state == PANEL_STRUT_REMOVE) return;
int sizes[4] = {0, 0, 0, 0};
sizes[state & PANEL_STRUT_BOTTOM ? 3 : 2] = h();
/* TODO: netwm_window_set_strut_partial() */
netwm_window_set_strut(fl_xid(this), sizes[0], sizes[1], sizes[2], sizes[3]);
}
void Panel::show(void) {
if(shown()) {
Fl_Window::show();
return;
}
int X, Y, W, H;
fl_open_display();
if(shown()) return;
/*
* hush known FLTK bug with XGetImage; a lot of errors will be print when menu icons goes
* outside screen; this also make ede-panel, at some point, unresponsible
* hush known FLTK bug with XGetImage; a lot of errors will be printed when menu icons goes
* outside screen; this can stuck ede-panel at some point
*/
XSetErrorHandler((XErrorHandler) xerror_handler);
update_size_and_pos(true, true);
/* position it */
/* collect messages */
Fl::add_handler(x_events);
}
void Panel::hide(void) {
Fl::remove_handler(x_events);
set_strut(PANEL_STRUT_REMOVE);
/* clear loaded widgets */
mgr.clear(this);
/* clear whatever was left out, but was not part of applet manager */
clear();
save_config();
Fl_Window::hide();
}
void Panel::update_size_and_pos(bool create_xid, bool update_strut) {
int X, Y, W, H;
/* figure out screen dimensions */
if(!netwm_workarea_get_size(X, Y, W, H))
Fl::screen_xywh(X, Y, W, H);
update_size_and_pos(create_xid, update_strut, X, Y, W, H);
}
void Panel::update_size_and_pos(bool create_xid, bool update_strut, int X, int Y, int W, int H) {
/* do not update ourself if we screen sizes are the same */
if(screen_x == X && screen_y == Y && screen_w == W && screen_h == H)
return;
screen_x = X;
screen_y = Y;
screen_w = W;
@ -348,33 +460,37 @@ void Panel::show(void) {
size(W, DEFAULT_PANEL_H);
do_layout();
window_xid_create(this, make_me_dock);
if(create_xid) window_xid_create(this, make_me_dock);
/* position it, this is done after XID was created */
if(vpos == PANEL_POSITION_BOTTOM) {
position(X, screen_h - h());
if(width_perc >= 100)
netwm_window_set_strut(fl_xid(this), 0, 0, 0, h());
if(width_perc >= 100 && update_strut)
set_strut(PANEL_STRUT_REMOVE | PANEL_STRUT_BOTTOM);
} else {
/* FIXME: this does not work well with edewm (nor pekwm). kwin do it correctly. */
position(X, Y);
if(width_perc >= 100)
netwm_window_set_strut(fl_xid(this), 0, 0, h(), 0);
/*
* I'm not sure what the hell is going on here; if 'y == 0', X will
* move panel few pixels down, even if FLTK is reporting y() == 0.
* Seems like 1 will solve this.
*/
position(X, Y == 0 ? 1 : Y);
if(width_perc >= 100 && update_strut)
set_strut(PANEL_STRUT_REMOVE | PANEL_STRUT_TOP);
}
}
void Panel::hide(void) {
save_config();
}
int Panel::handle(int e) {
return Fl_Window::handle(e);
#if 0
switch(e) {
case FL_PUSH:
clicked = Fl::belowmouse();
if(clicked == this)
clicked = 0;
else if(clicked && clicked->takesevents())
else if(clicked && Fl::event_inside(clicked) && clicked->takesevents())
clicked->handle(e);
/* record push position for possible child drag */
@ -383,27 +499,32 @@ int Panel::handle(int e) {
return 1;
case FL_DRAG: {
if(!can_drag) return 1;
/* send drag events to children and do not drag panel in the mean time */
if(clicked && clicked != this && Fl::event_inside(clicked) && clicked->takesevents()) {
cursor(FL_CURSOR_MOVE);
return clicked->handle(e);
} else {
printf("XXXy %p %p\n", clicked, this);
if(!can_drag) return 1;
cursor(FL_CURSOR_MOVE);
/* are moving the panel; only vertical moving is supported */
cursor(FL_CURSOR_MOVE);
/* snap it to the top or bottom, depending on pressed mouse location */
if(Fl::event_y_root() <= screen_h_half && y() > screen_h_half) {
position(x(), screen_y);
if(width_perc >= 100)
set_strut(PANEL_STRUT_TOP);
vpos = PANEL_POSITION_TOP;
}
/* snap it to the top or bottom, depending on pressed mouse location */
if(Fl::event_y_root() <= screen_h_half && y() > screen_h_half) {
position(x(), screen_y);
if(width_perc >= 100)
netwm_window_set_strut(fl_xid(this), 0, 0, h(), 0);
vpos = PANEL_POSITION_TOP;
}
if(Fl::event_y_root() > screen_h_half && y() < screen_h_half) {
position(x(), screen_h - h());
if(width_perc >= 100)
netwm_window_set_strut(fl_xid(this), 0, 0, 0, h());
vpos = PANEL_POSITION_BOTTOM;
if(Fl::event_y_root() > screen_h_half && y() < screen_h_half) {
position(x(), screen_h - h());
if(width_perc >= 100)
set_strut(PANEL_STRUT_BOTTOM);
vpos = PANEL_POSITION_BOTTOM;
}
return 1;
}
return 1;
}
case FL_RELEASE:
@ -422,53 +543,68 @@ int Panel::handle(int e) {
return 1;
/* fallthrough */
}
return Fl_Window::handle(e);
#endif
}
void Panel::load_applets(void) {
void Panel::load_applets(const char *applets, PanelResource *res) {
mgr.clear(this);
/*
* Hardcoded order, unless configuration file was found. For easier and uniform parsing
* (similar string is expected from configuration), fallback is plain string.
*/
static const char *fallback =
#ifndef EDE_PANEL_LOCAL_APPLETS
/* FIXME: hardcoded order */
static const char *applets[] = {
"start_menu.so",
"quick_launch.so",
"pager.so",
"hider.so",
"clock.so",
"taskbar.so",
"keyboard_layout.so",
"cpu_monitor.so",
#ifdef __linux__
"mem_monitor.so",
#endif
"system_tray.so",
0
};
"start_menu,"
"quick_launch,"
"pager,"
"clock,"
"taskbar,"
"keyboard_layout,"
"battery_monitor,"
"cpu_monitor,"
# ifdef __linux__
"mem_monitor,"
# endif
"system_tray"
#else /* EDE_PANEL_LOCAL_APPLETS */
"./applets/start-menu/start_menu,"
"./applets/quick-launch/quick_launch,"
"./applets/pager/pager,"
"./applets/clock/clock,"
"./applets/taskbar/taskbar,"
"./applets/keyboard-layout/keyboard_layout,"
"./applets/battery-monitor/battery_monitor,"
"./applets/cpu-monitor/cpu_monitor,"
# ifdef __linux__
"./applets/mem-monitor/mem_monitor,"
# endif
"./applets/system-tray/system_tray"
#endif /* EDE_PANEL_LOCAL_APPLETS */
;
String dir = Resource::find_data("panel-applets");
if(dir.empty())
return;
E_RETURN_IF_FAIL(!dir.empty());
char *dup = strdup(applets ? applets : fallback);
E_RETURN_IF_FAIL(dup != NULL);
String tmp;
for(int i = 0; applets[i]; i++) {
tmp = build_filename(dir.c_str(), applets[i]);
mgr.load(tmp.c_str());
char path[PATH_MAX];
for(char *tok = strtok(dup, ","); tok; tok = strtok(NULL, ",")) {
tok = str_trim(tok);
#ifndef EDE_PANEL_LOCAL_APPLETS
snprintf(path, sizeof(path), "%s" E_DIR_SEPARATOR_STR "%s" APPLET_EXTENSION, dir.c_str(), tok);
#else
/* only for testing, so path separator is hardcoded */
snprintf(path, sizeof(path), "%s" APPLET_EXTENSION, tok);
#endif
mgr.load(path);
}
mgr.fill_group(this);
#else
mgr.load("./applets/start-menu/start_menu.so");
mgr.load("./applets/quick-launch/quick_launch.so");
mgr.load("./applets/pager/pager.so");
mgr.load("./applets/hider/hider.so");
mgr.load("./applets/clock/clock.so");
mgr.load("./applets/taskbar/taskbar.so");
mgr.load("./applets/keyboard-layout/keyboard_layout.so");
mgr.load("./applets/cpu-monitor/cpu_monitor.so");
mgr.load("./applets/mem-monitor/mem_monitor.so");
mgr.load("./applets/system-tray/system_tray.so");
mgr.fill_group(this);
#endif
free(dup);
mgr.fill_group(this, res);
}
/* TODO: can be better */

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __PANEL_H__
#define __PANEL_H__
@ -14,9 +34,20 @@ enum {
PANEL_POSITION_BOTTOM
};
/* combination of what to do with strut data */
enum {
PANEL_STRUT_REMOVE = (1 << 1),
PANEL_STRUT_BOTTOM = (1 << 2),
PANEL_STRUT_TOP = (1 << 3)
};
class Hider;
class Panel : public PanelWindow {
private:
Fl_Widget *clicked;
Hider *hider;
int vpos;
int sx, sy;
int screen_x, screen_y, screen_w, screen_h, screen_h_half;
@ -28,14 +59,16 @@ private:
void read_config(void);
void save_config(void);
void do_layout(void);
void set_strut(short state);
public:
Panel();
void show(void);
void hide(void);
void update_size_and_pos(bool create_xid, bool update_strut);
void update_size_and_pos(bool create_xid, bool update_strut, int X, int Y, int W, int H);
int handle(int e);
void load_applets(void);
void load_applets(const char *applets, PanelResource *res = 0);
int panel_w(void) { return w(); }
int panel_h(void) { return h(); }

View File

@ -13,8 +13,8 @@ SubDir TOP ede-panel applets ;
# SubInclude TOP ede-panel applets demo ;
SubInclude TOP ede-panel applets clock ;
SubInclude TOP ede-panel applets cpu-monitor ;
SubInclude TOP ede-panel applets hider ;
SubInclude TOP ede-panel applets mem-monitor ;
SubInclude TOP ede-panel applets battery-monitor ;
SubInclude TOP ede-panel applets keyboard-layout ;
SubInclude TOP ede-panel applets pager ;
SubInclude TOP ede-panel applets quick-launch ;

View File

@ -0,0 +1,302 @@
/*
* Copyright (C) 2013-2016 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <FL/Fl_Box.H>
#include <edelib/Nls.h>
#include "Applet.h"
#ifdef EDELIB_HAVE_DBUS
#include <edelib/EdbusConnection.h>
#include <edelib/EdbusMessage.h>
#include <edelib/EdbusList.h>
#include <edelib/EdbusObjectPath.h>
#include <edelib/EdbusData.h>
#include <edelib/List.h>
#include <edelib/Debug.h>
#include <edelib/IconLoader.h>
EDELIB_NS_USING(EdbusConnection)
EDELIB_NS_USING(EdbusMessage)
EDELIB_NS_USING(EdbusList)
EDELIB_NS_USING(EdbusObjectPath)
EDELIB_NS_USING(EdbusData)
EDELIB_NS_USING(EdbusVariant)
EDELIB_NS_USING(IconLoader)
EDELIB_NS_USING(ICON_SIZE_SMALL)
EDELIB_NS_USING(list)
EDELIB_NS_USING(EDBUS_SYSTEM)
#define UPOWER_TYPE_BATTERY 2
#define UPOWER_STATE_CHARGING 1
#define UPOWER_STATE_DISCHARGING 2
#define UPOWER_STATE_EMPTY 3
#define UPOWER_STATE_CHARGED 4
#define UPOWER_SERVICE "org.freedesktop.UPower"
#define UPOWER_INTERFACE "org.freedesktop.UPower.Device"
#define UPOWER_PATH "/org/freedesktop/UPower"
#define BATTERY_MIN 10 /* minimal time before icon to BATTERY_CAUTION_IMG was changed */
#define BATTERY_IMG "battery"
#define BATTERY_CAUTION_IMG "battery-caution"
#define BATTERY_NO_CONNECTION "dialog-warning"
typedef list<EdbusObjectPath> BatteryList;
typedef list<EdbusObjectPath>::iterator BatteryListIt;
/*
* For now all query-ing is done via UPower. Applet is support multiple batteries, but
* status will be reported as cumulative state all of them.
* TODO: add support for other methods, like DeviceKit (is this obsolete??)
*/
class BatteryMonitor : public Fl_Box {
private:
const char *bimg;
char tip[128];
EdbusConnection con;
BatteryList batts;
public:
BatteryMonitor() : Fl_Box(0, 0, 30, 25), bimg(0) {
box(FL_FLAT_BOX);
if(!scan_and_init()) {
set_icon(0, true);
tooltip(_("Failed to query battery status"));
}
}
EdbusConnection &connection() { return con; }
void tooltip_printf(const char *fmt, ...);
int scan_and_init(void);
int update_icon_and_tooltip(void);
void set_icon(double percentage, bool failure = false);
BatteryList &get_batteries(void);
};
static bool bus_property_get(EdbusConnection &con,
const char *service,
const char *path,
const char *iface,
const char *prop,
EdbusMessage *ret)
{
EdbusMessage msg;
msg.create_method_call(service, path, "org.freedesktop.DBus.Properties", "Get");
msg << EdbusData::from_string(iface);
msg << EdbusData::from_string(prop);
E_RETURN_VAL_IF_FAIL(con.send_with_reply_and_block(msg, 1000, *ret), false);
E_RETURN_VAL_IF_FAIL(ret->size() == 1, false);
return true;
}
static bool is_battery(EdbusConnection &con, const char *path) {
EdbusMessage reply;
E_RETURN_VAL_IF_FAIL(bus_property_get(con, UPOWER_SERVICE, path, UPOWER_INTERFACE, "Type", &reply), false);
EdbusMessage::const_iterator it = reply.begin();
E_RETURN_VAL_IF_FAIL(it->is_variant(), false);
EdbusVariant v = it->to_variant();
E_RETURN_VAL_IF_FAIL(v.value.is_uint32(), false);
return v.value.to_uint32() == UPOWER_TYPE_BATTERY;
}
static bool get_percentage(EdbusConnection &con, const char *path, double *ret) {
EdbusMessage reply;
E_RETURN_VAL_IF_FAIL(bus_property_get(con, UPOWER_SERVICE, path, UPOWER_INTERFACE, "Percentage", &reply), false);
EdbusMessage::const_iterator it = reply.begin();
E_RETURN_VAL_IF_FAIL(it->is_variant(), false);
EdbusVariant v = it->to_variant();
E_RETURN_VAL_IF_FAIL(v.value.is_double(), false);
*ret = v.value.to_double();
return true;
}
static bool get_state(EdbusConnection &con, const char *path, int *ret) {
EdbusMessage reply;
E_RETURN_VAL_IF_FAIL(bus_property_get(con, UPOWER_SERVICE, path, UPOWER_INTERFACE, "State", &reply), false);
EdbusMessage::const_iterator it = reply.begin();
E_RETURN_VAL_IF_FAIL(it->is_variant(), false);
EdbusVariant v = it->to_variant();
E_RETURN_VAL_IF_FAIL(v.value.is_uint32(), false);
*ret = v.value.to_uint32();
return true;
}
static const char *get_state_str(EdbusConnection &con, const char *path) {
const char * fallback = _("unknown");
int ret;
E_RETURN_VAL_IF_FAIL(get_state(con, path, &ret), fallback);
switch(ret) {
case UPOWER_STATE_CHARGED: return _("charged");
case UPOWER_STATE_CHARGING: return _("charging");
case UPOWER_STATE_DISCHARGING: return _("discharging");
case UPOWER_STATE_EMPTY: return _("empty");
}
return fallback;
}
static int signal_cb(const EdbusMessage *msg, void *data) {
/* in case some org.freedesktop.DBus (like NameAcquired) received */
if(strcmp(msg->interface(), UPOWER_INTERFACE) != 0)
return 0;
BatteryMonitor *self = (BatteryMonitor*)data;
return self->update_icon_and_tooltip();
}
void BatteryMonitor::tooltip_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vsnprintf(tip, sizeof(tip), fmt, args);
va_end(args);
tooltip(tip);
}
int BatteryMonitor::scan_and_init(void) {
if(con.connected()) return 1;
E_RETURN_VAL_IF_FAIL(con.connect(EDBUS_SYSTEM), 0);
/* get battery devices */
EdbusMessage msg, reply;
msg.create_method_call(UPOWER_SERVICE, UPOWER_PATH, UPOWER_SERVICE, "EnumerateDevices");
E_RETURN_VAL_IF_FAIL(con.send_with_reply_and_block(msg, 1000, reply), 0);
E_RETURN_VAL_IF_FAIL(reply.size() == 1, 0);
EdbusMessage::const_iterator it = reply.begin();
E_RETURN_VAL_IF_FAIL(it->is_array(), 0);
EdbusList arr = it->to_array();
it = arr.begin();
EdbusMessage::const_iterator ite = arr.end();
for(; it != ite; ++it) {
if(!it->is_object_path()) continue;
EdbusObjectPath p = it->to_object_path();
if(is_battery(con, p.path())) {
/* filters so signal_cb() doesn't get clobbered with uninterested dbus signals */
con.add_signal_match(p.path(), UPOWER_INTERFACE, "Changed");
//con.add_signal_match(p.path(), UPOWER_SERVICE, "DeviceChanged");
batts.push_back(p);
}
}
update_icon_and_tooltip();
/* ready to receive signals */
con.signal_callback(signal_cb, this);
con.setup_listener_with_fltk();
return 1;
}
int BatteryMonitor::update_icon_and_tooltip(void) {
/* in case connection failed somehow */
if(!con.connected()) {
label("0");
return 0;
}
E_RETURN_VAL_IF_FAIL(batts.size() > 0, 0);
double p = 0, ret = 0;
if(batts.size() == 1) {
E_RETURN_VAL_IF_FAIL(get_percentage(con, batts.front().path(), &ret), 0);
p = ret;
tooltip_printf(_("Battery %s: %i%%"), get_state_str(con, batts.front().path()), (int)ret);
} else {
for(BatteryListIt it = batts.begin(), ite = batts.end(); it != ite; ++it) {
if(!get_percentage(con, it->path(), &ret)) continue;
p += ret;
}
p /= batts.size();
tooltip_printf(_("%i batteries: %i%%"), batts.size(), (int)p);
}
set_icon(p);
/* returning state is mainly for signal_cb() */
return 1;
}
#define BATTERY_MIN 10
void BatteryMonitor::set_icon(double percentage, bool failure) {
if(E_UNLIKELY(IconLoader::inited() == false)) {
char buf[8];
snprintf(buf, sizeof(buf), "%i%%", (int)percentage);
copy_label(buf);
return;
}
const char *icon;
if(failure)
icon = BATTERY_NO_CONNECTION;
else
icon = (percentage >= BATTERY_MIN) ? BATTERY_IMG : BATTERY_CAUTION_IMG;
/* small check to prevent image loading when not needed */
if(icon == bimg) return;
IconLoader::set(this, icon, ICON_SIZE_SMALL);
bimg = icon;
}
#else /* EDELIB_HAVE_DBUS */
class BatteryMonitor : public Fl_Box {
public:
BatteryMonitor() : Fl_Box(0, 0, 30, 25) {
tooltip(_("Battery status not available"));
label("bat");
}
};
#endif
EDE_PANEL_APPLET_EXPORT (
BatteryMonitor,
EDE_PANEL_APPLET_OPTION_ALIGN_RIGHT,
"Battery monitor",
"0.1",
"empty",
"Sanel Zukan"
)

View File

@ -0,0 +1,13 @@
#
# $Id: Jamfile 3515 2013-01-09 16:01:35Z karijes $
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2013 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP ede-panel applets battery-monitor ;
PanelApplet battery_monitor : BatteryMonitor.cpp : $(EDELIB_DBUS_LIB) ;

View File

@ -9,6 +9,10 @@
* For ede-panel by Sanel Zukan 2009
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <limits.h>
#include <unistd.h>
#include <stdarg.h>
@ -26,22 +30,27 @@
# include <sys/sysinfo.h>
#endif
#ifdef HAVE_KSTAT_H
#ifdef HAVE_KSTAT
# include <kstat.h>
# include <sys/sysinfo.h>
# include <string.h> /* strncmp */
#endif
#ifdef __FreeBSD__
#if defined(__FreeBSD__) || defined(__OpenBSD__)
# include <sys/param.h>
# include <sys/sysctl.h>
# if __FreeBSD_version < 500101
# include <sys/dkstat.h>
# if defined(__OpenBSD__)
# include <sys/sched.h>
# else
# include <sys/resource.h>
# if __FreeBSD_version < 500101
# include <sys/dkstat.h>
# else
# include <sys/resource.h>
# endif
# endif
# include <sys/stat.h>
#endif
#include "Applet.h"
#include "CpuMonitor.h"
#ifdef __FreeBSD__
@ -149,9 +158,9 @@ void CPUMonitor::clear()
if(!cpu) return;
for (int i = 0; i < samples(); i++)
delete cpu[i];
delete [] cpu[i];
delete cpu;
delete [] cpu;
cpu = 0;
m_old_samples = -1;
@ -336,11 +345,10 @@ void CPUMonitor::get_cpu_info() {
#endif /* linux */
#ifdef HAVE_KSTAT_H
#ifdef HAVE_KSTAT
# ifdef HAVE_OLD_KSTAT
# define ui32 ul
#endif
static kstat_ctl_t *kc = NULL;
static kid_t kcid;
kid_t new_kcid;

View File

@ -2,6 +2,7 @@
#define __CPUMONITOR_H__
#include <FL/Fl_Box.H>
#include "Applet.h"
/*
#ifdef HAVE_KSTAT_H

View File

@ -10,4 +10,4 @@
SubDir TOP ede-panel applets cpu-monitor ;
PanelApplet cpu_monitor : CpuMonitor.cpp ;
PanelApplet cpu_monitor : CpuMonitor.cpp : $(KSTAT_LIBS) ;

View File

@ -1,13 +0,0 @@
#
# $Id: Jamfile 2864 2009-10-03 07:49:30Z karijes $
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2012 EDE Authors.
#
# This program is licensed under terms of the
# GNU General Public License version 2 or newer.
# See COPYING for details.
SubDir TOP ede-panel applets hider ;
PanelApplet hider : Hider.cpp ;

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2011-2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "Applet.h"
#ifdef HAVE_CONFIG_H
@ -10,6 +30,7 @@
#include <FL/Fl.H>
#include <stdio.h> /* needed for XKBrules.h */
#include <stdlib.h>
#ifdef HAVE_XKBRULES
# include <X11/XKBlib.h>
@ -61,11 +82,12 @@ static KeyLayoutList keylayout_objects;
#ifdef HAVE_XKBRULES
/* Xkb does not provide this */
static void xkbrf_names_prop_free(XkbRF_VarDefsRec &vd, char *tmp) {
XFree(tmp);
XFree(vd.model);
XFree(vd.layout);
XFree(vd.options);
XFree(vd.variant);
if(tmp) free(tmp);
if(vd.model) XFree(vd.model);
if(vd.layout) XFree(vd.layout);
if(vd.options) XFree(vd.options);
if(vd.variant) XFree(vd.variant);
if(vd.extra_names) XFree(vd.extra_names);
}
#endif
@ -172,8 +194,10 @@ void KeyLayout::do_key_layout(void) {
if(XkbRF_GetNamesProp(fl_display, &tmp, &vd)) {
/* do nothing if layout do not exists or the same was catched */
if(!vd.layout || (curr_layout == vd.layout))
if(!vd.layout || (curr_layout == vd.layout)) {
xkbrf_names_prop_free(vd, tmp);
return;
}
/* just store it, so update_flag() can do the rest */
curr_layout = vd.layout;

View File

@ -1,72 +1,79 @@
/*
* $Id: Panel.cpp 3512 2013-01-09 13:45:49Z karijes $
*
* Copyright (C) 2012-2013 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <FL/Fl_Box.H>
#include "Applet.h"
#include <edelib/Nls.h>
#if defined(linux)
#include <sys/sysinfo.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <edelib/Color.h>
#include <edelib/Missing.h>
#include "Applet.h"
#include "MemMonitor.h"
EDELIB_NS_USING(color_rgb_to_fltk)
#define UPDATE_INTERVAL 1.0f
#define UPDATE_INTERVAL 2.0f
#define STR_CMP(first, second, n) (strncmp(first, second, n) == 0)
static int height_from_perc(int perc, int h) {
class MemMonitor : public Fl_Box {
private:
int mem_usedp, swap_usedp;
public:
MemMonitor() : Fl_Box(0, 0, 45, 25), mem_usedp(0), swap_usedp(0) {
box(FL_THIN_DOWN_BOX);
update_status();
}
void update_status(void);
void draw(void);
int handle(int e);
};
inline int height_from_perc(int perc, int h) {
return (perc * h) / 100;
}
static long get_number(const char *ln) {
char *s = edelib_strndup(ln, 128);
int i = 1;
for(char *p = strtok(s, " "); p; p = strtok(NULL, " "), i++) {
if(i == 2) {
long ret = atol(p);
free(s);
return ret;
}
}
free(s);
return 0;
}
static void mem_timeout_cb(void *d) {
((MemMonitor*)d)->update_status();
Fl::repeat_timeout(UPDATE_INTERVAL, mem_timeout_cb, d);
}
MemMonitor::MemMonitor() : Fl_Box(0, 0, 45, 25), mem_usedp(0), swap_usedp(0) {
box(FL_THIN_DOWN_BOX);
}
void MemMonitor::update_status(void) {
FILE *fd = fopen("/proc/meminfo", "r");
if(!fd) return;
struct sysinfo sys;
if(sysinfo(&sys) != 0) return;
long mem_total, mem_free, swap_total, swap_free;
mem_total = mem_free = swap_total = swap_free = 0;
char buf[128];
while(fgets(buf, 128, fd) != 0) {
if(STR_CMP(buf, "MemTotal:", 9))
mem_total = get_number(buf);
else if(STR_CMP(buf, "MemFree:", 8))
mem_free = get_number(buf);
else if(STR_CMP(buf, "SwapTotal:", 10))
swap_total = get_number(buf);
else if(STR_CMP(buf, "SwapFree:", 9))
swap_free = get_number(buf);
}
fclose(fd);
mem_total = (float)sys.totalram * (float)sys.mem_unit / 1048576.0f;
mem_free = (float)sys.freeram * (float)sys.mem_unit / 1048576.0f;
swap_total = (float)sys.totalswap * (float)sys.mem_unit / 1048576.0f;
swap_free = (float)sys.freeswap * (float)sys.mem_unit / 1048576.0f;
mem_usedp = 100 - (int)(((float)mem_free / (float)mem_total) * 100);
swap_usedp = 100 - (int)(((float)swap_total / (float)swap_free) * 100);
swap_usedp = 100 - (int)(((float)swap_free / (float)swap_total) * 100);
static char tip[100];
snprintf(tip, sizeof(tip), "Memory used: %i%%\nSwap used: %i%%", mem_usedp, swap_usedp);
snprintf(tip, sizeof(tip), _("Memory used: %i%%\nSwap used: %i%%"), mem_usedp, swap_usedp);
tooltip(tip);
redraw();
@ -105,11 +112,24 @@ int MemMonitor::handle(int e) {
return Fl_Box::handle(e);
}
#else
class MemMonitor : public Fl_Box {
public:
MemMonitor() : Fl_Box(0, 0, 45, 25) {
box(FL_THIN_DOWN_BOX);
label("n/a");
tooltip(_("Memory information not available for this platform"));
}
};
#endif /* linux */
EDE_PANEL_APPLET_EXPORT (
MemMonitor,
EDE_PANEL_APPLET_OPTION_ALIGN_RIGHT,
"Memory monitor",
"0.1",
"0.2",
"empty",
"Sanel Zukan"
)

View File

@ -1,17 +0,0 @@
#ifndef __MEMMONITOR_H__
#define __MEMMONITOR_H__
#include <FL/Fl_Box.H>
class MemMonitor : public Fl_Box {
private:
int mem_usedp, swap_usedp;
public:
MemMonitor();
void update_status(void);
void draw(void);
int handle(int e);
};
#endif

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "Applet.h"
#include <ctype.h>

View File

@ -84,9 +84,10 @@ public:
const char *get_id(void) { return id ? id->c_str() : NULL; }
unsigned int get_age(void) { return age; }
const char *get_name(void) { return name ? name->c_str() : NULL; }
const char *get_icon(void) { return icon ? icon->c_str() : NULL; }
const char *get_exec(void) { return exec_cmd ? exec_cmd->c_str() : NULL; }
const char *get_name(void) { return name ? name->c_str() : NULL; }
const char *get_icon(void) { return icon ? icon->c_str() : NULL; }
const char *get_exec(void) { return exec_cmd ? exec_cmd->c_str() : NULL; }
const char *get_comment(void) { return comment ? comment->c_str() : NULL; }
};
/* remove duplicate items in the list, by looking at DesktopEntry id */

View File

@ -12,10 +12,14 @@ SubDir TOP ede-panel applets start-menu ;
MENU_SRC = XdgMenuReader.cpp DesktopEntry.cpp MenuRules.cpp ;
Library libmenu : $(MENU_SRC) ;
ObjectC++Flags $(MENU_SRC) : -fPIC $(FLTKINCLUDE) -I [ FDirName $(TOP) ede-panel ] $(EDELIBINCLUDE) ;
if $(MENU_TESTS) {
Library libmenu : $(MENU_SRC) ;
ObjectC++Flags $(MENU_SRC) : -fPIC $(FLTKINCLUDE) -I [ FDirName $(TOP) ede-panel ] $(EDELIBINCLUDE) ;
PanelApplet start_menu : StartMenu.cpp : -L$(SUBDIR) -lmenu ;
PanelApplet start_menu : StartMenu.cpp : -L$(SUBDIR) -lmenu ;
EdeProgram ede-menu-spec-test : ede-menu-spec-test.cpp ;
LinkAgainstAsFirst ede-menu-spec-test : -L$(SUBDIR) -lmenu ;
EdeProgram ede-menu-spec-test : ede-menu-spec-test.cpp ;
LinkAgainstAsFirst ede-menu-spec-test : -L$(SUBDIR) -lmenu ;
} else {
PanelApplet start_menu : StartMenu.cpp $(MENU_SRC) ;
}

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __MENURULES_H__
#define __MENURULES_H__
@ -8,7 +28,7 @@ EDELIB_NS_USING(list)
EDELIB_NS_USING(String)
struct MenuRules;
struct DesktopEntry;
class DesktopEntry;
typedef list<MenuRules*> MenuRulesList;
typedef list<MenuRules*>::iterator MenuRulesListIt;

View File

@ -1,21 +1,64 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "Applet.h"
#include <time.h>
#include <FL/Fl.H>
#include <FL/fl_draw.H>
#include <edelib/MenuBase.h>
#include <edelib/Debug.h>
#include <edelib/Nls.h>
#include <edelib/Debug.h>
#include <edelib/StrUtil.h>
#include "XdgMenuReader.h"
#include "ede-icon.h"
/* by default is enabled */
#define EDE_PANEL_MENU_AUTOUPDATE 1
#ifdef EDE_PANEL_MENU_AUTOUPDATE
# include <edelib/DirWatch.h>
EDELIB_NS_USING(DirWatch)
EDELIB_NS_USING_LIST(4, (DW_CREATE, DW_MODIFY, DW_DELETE, DW_REPORT_RENAME))
/* when menu needs to be update, after how long to do real update */
# define MENU_UPDATE_TIMEOUT 5.0
/* elapsed seconds between changes reports from DirWatch; to prevent event throttling */
# define MENU_UPDATE_DIFF 5
#endif
EDELIB_NS_USING(MenuBase)
EDELIB_NS_USING(str_ends)
/* some of this code was ripped from Fl_Menu_Button.cxx */
class StartMenu : public MenuBase {
private:
MenuItem *mcontent;
XdgMenuContent *mcontent, *mcontent_pending;
time_t last_reload;
bool menu_opened;
void setup_menu(XdgMenuContent *m);
public:
StartMenu();
~StartMenu();
@ -23,9 +66,35 @@ public:
void popup(void);
void draw(void);
int handle(int e);
void reload_menu(void);
bool can_reload(void);
};
StartMenu::StartMenu() : MenuBase(0, 0, 80, 25, "EDE"), mcontent(NULL) {
#ifdef EDE_PANEL_MENU_AUTOUPDATE
static void menu_update_cb(void *data) {
StartMenu *m = (StartMenu*)data;
m->reload_menu();
E_DEBUG(E_STRLOC ": Scheduled menu update done\n");
}
static void folder_changed_cb(const char *dir, const char *w, int flags, void *data) {
StartMenu *m = (StartMenu*)data;
/* skip file renaming */
if(flags == DW_REPORT_RENAME) return;
if(w == NULL) w = "<none>";
/* add timeout for update so all filesystem changes gets applied */
if(str_ends(w, ".desktop") && m->can_reload()) {
E_DEBUG(E_STRLOC ": Scheduled menu update due changes inside inside '%s' folder ('%s':%i) in %i secs.\n", dir, w, flags, MENU_UPDATE_TIMEOUT);
Fl::add_timeout(MENU_UPDATE_TIMEOUT, menu_update_cb, m);
}
}
#endif
StartMenu::StartMenu() : MenuBase(0, 0, 80, 25, "EDE"), mcontent(NULL), mcontent_pending(NULL), last_reload(0), menu_opened(false) {
down_box(FL_NO_BOX);
labelfont(FL_HELVETICA_BOLD);
labelsize(14);
@ -33,21 +102,51 @@ StartMenu::StartMenu() : MenuBase(0, 0, 80, 25, "EDE"), mcontent(NULL) {
tooltip(_("Click here to choose and start common programs"));
/* load menu */
mcontent = xdg_menu_load();
setup_menu(mcontent);
if(mcontent) {
/* skip the first item, since it often contains only one submenu */
if(mcontent->submenu()) {
MenuItem *mc = mcontent + 1;
menu(mc);
} else {
menu(mcontent);
}
}
#ifdef EDE_PANEL_MENU_AUTOUPDATE
/*
* setup listeners on menu folders
* TODO: this list is constructed twice: the first time when menu was loaded and now
*/
StrList lst;
xdg_menu_applications_location(lst);
DirWatch::init();
StrListIt it = lst.begin(), ite = lst.end();
for(; it != ite; ++it)
DirWatch::add(it->c_str(), DW_CREATE | DW_MODIFY | DW_DELETE);
DirWatch::callback(folder_changed_cb, this);
#endif
}
StartMenu::~StartMenu() {
xdg_menu_delete(mcontent);
if(mcontent) xdg_menu_delete(mcontent);
if(mcontent_pending) xdg_menu_delete(mcontent_pending);
#ifdef EDE_PANEL_MENU_AUTOUPDATE
DirWatch::shutdown();
#endif
}
void StartMenu::setup_menu(XdgMenuContent *m) {
if(m == NULL) {
menu(NULL);
return;
}
MenuItem *item = xdg_menu_to_fltk_menu(m);
/* skip the first item, since it often contains only one submenu */
if(item && item->submenu()) {
menu(item + 1);
} else {
menu(item);
}
}
static StartMenu *pressed_menu_button = 0;
@ -78,13 +177,18 @@ void StartMenu::draw(void) {
}
void StartMenu::popup(void) {
menu_opened = true;
const MenuItem *m;
pressed_menu_button = this;
redraw();
#if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 3)
Fl_Widget *mb = this;
Fl::watch_widget_pointer(mb);
#endif
if(!box() || type())
m = menu()->popup(Fl::event_x(), Fl::event_y(), label(), mvalue(), this);
else
@ -92,7 +196,25 @@ void StartMenu::popup(void) {
picked(m);
pressed_menu_button = 0;
#if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 3)
Fl::release_widget_pointer(mb);
#endif
menu_opened = false;
#ifdef EDE_PANEL_MENU_AUTOUPDATE
/* if we have menu that wants to be updated, swap them as soon as menu window was closed */
if(mcontent_pending) {
XdgMenuContent *tmp = mcontent;
mcontent = mcontent_pending;
setup_menu(mcontent);
mcontent_pending = tmp;
xdg_menu_delete(mcontent_pending);
mcontent_pending = NULL;
}
#endif
}
int StartMenu::handle(int e) {
@ -158,11 +280,39 @@ int StartMenu::handle(int e) {
return 0;
}
/* to prevent throttling of dirwatch events */
bool StartMenu::can_reload(void) {
#ifdef EDE_PANEL_MENU_AUTOUPDATE
time_t c, diff;
c = time(NULL);
diff = (time_t)difftime(c, last_reload);
last_reload = c;
if(diff >= MENU_UPDATE_DIFF) return true;
#endif
return false;
}
void StartMenu::reload_menu(void) {
#ifdef EDE_PANEL_MENU_AUTOUPDATE
if(menu_opened) {
mcontent_pending = xdg_menu_load();
} else {
xdg_menu_delete(mcontent);
mcontent = xdg_menu_load();
setup_menu(mcontent);
}
#endif
}
EDE_PANEL_APPLET_EXPORT (
StartMenu,
EDE_PANEL_APPLET_OPTION_ALIGN_LEFT,
"Main menu",
"0.1",
"0.2",
"empty",
"Sanel Zukan"
)

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
@ -6,9 +26,7 @@
#include <FL/Fl_Shared_Image.H>
#include <edelib/TiXml.h>
#include <edelib/Debug.h>
#include <edelib/String.h>
#include <edelib/StrUtil.h>
#include <edelib/List.h>
#include <edelib/Util.h>
#include <edelib/FileTest.h>
#include <edelib/Directory.h>
@ -21,9 +39,7 @@
#include "MenuRules.h"
#include "XdgMenuReader.h"
EDELIB_NS_USING(String)
EDELIB_NS_USING(DesktopFile)
EDELIB_NS_USING(list)
EDELIB_NS_USING(IconLoader)
EDELIB_NS_USING(system_config_dirs)
EDELIB_NS_USING(system_data_dirs)
@ -204,25 +220,11 @@ static void menu_parse_context_append_desktop_files(MenuParseContext *ctx, const
static void menu_parse_context_append_desktop_files_from_xdg_data_dirs(MenuParseContext *ctx) {
StrList lst;
if(system_data_dirs(lst) < 1)
return;
xdg_menu_applications_location(lst);
StrListIt it = lst.begin(), it_end = lst.end();
String tmp;
for(; it != it_end; ++it) {
tmp = build_filename((*it).c_str(), "applications");
menu_parse_context_append_desktop_files(ctx, tmp.c_str(), tmp.c_str());
}
/*
* Add user directory too; the spec is unclear about this, but official menu spec tests
* requires it. Also, users will be able to add menu items without superuser permissions.
*/
String user_dir = user_data_dir();
tmp = build_filename(user_dir.c_str(), "applications");
menu_parse_context_append_desktop_files(ctx, tmp.c_str(), tmp.c_str());
for(; it != it_end; ++it)
menu_parse_context_append_desktop_files(ctx, it->c_str(), it->c_str());
}
static void scan_include_exclude_tag(TiXmlNode *elem, MenuRulesList &rules) {
@ -547,8 +549,8 @@ static MenuContext *menu_parse_context_to_menu_context(MenuParseContext *m,
* figure out the name first; if returns false, either menu should not be displayed, or something
* went wrong
*/
String *n, *ic;
bool should_be_displayed;
String *n = NULL, *ic = NULL;
bool should_be_displayed = false;
if(!menu_context_construct_name_and_get_icon(m, top, &n, &ic, &should_be_displayed))
return NULL;
@ -568,7 +570,6 @@ static MenuContext *menu_parse_context_to_menu_context(MenuParseContext *m,
ctx->name = n;
ctx->icon = ic;
ctx->display_it = should_be_displayed;
//E_DEBUG("+ Menu: %s %i\n", ctx->name->c_str(), m->include_rules.size());
/* fill MenuContext items, depending on what list was passed */
@ -799,7 +800,7 @@ static TiXmlNode *load_menu_file(TiXmlDocument &doc) {
String tmp;
StrListIt it = paths.begin(), it_end = paths.end();
for(; it != paths.end(); ++it) {
for(; it != it_end; ++it) {
tmp = build_filename((*it).c_str(), "menus", menu_file.c_str());
if(doc.LoadFile(tmp.c_str()))
@ -868,9 +869,18 @@ void xdg_menu_dump_for_test_suite(void) {
menu_all_parse_lists_clear(pl, cl);
}
/* used only for xdg_menu_load() and xdg_menu_delete() */
static MenuParseList global_parse_list;
static MenuContextList global_context_list;
/* public API */
struct XdgMenuContent {
MenuItem *fltk_menu;
/*
* We are keeping them as fltk_menu references some objects, like text.
* This is since FLTK menu can't free label strings as MenuItem is plain struct.
*/
MenuParseList parse_list;
MenuContextList context_list;
};
static void item_cb(Fl_Widget*, void *en) {
DesktopEntry *entry = (DesktopEntry*)en;
@ -916,7 +926,7 @@ static unsigned int construct_edelib_menu(MenuContextList &lst, MenuItem *mi, un
mi[pos].labelsize_ = FL_NORMAL_SIZE;
mi[pos].labelcolor_ = FL_BLACK;
mi[pos].image(NULL);
MenuItem::init_extensions(&mi[pos]);
/* set image for menu */
if(cc->icon && IconLoader::inited()) {
@ -952,13 +962,16 @@ static unsigned int construct_edelib_menu(MenuContextList &lst, MenuItem *mi, un
mi[pos].labelfont_ = FL_HELVETICA;
mi[pos].labelsize_ = FL_NORMAL_SIZE;
mi[pos].labelcolor_ = FL_BLACK;
mi[pos].image(NULL);
MenuItem::init_extensions(&mi[pos]);
/* set image for menu item*/
if((*ds)->get_icon() && IconLoader::inited()) {
Fl_Image *img = IconLoader::get((*ds)->get_icon(), ICON_SIZE_SMALL);
mi[pos].image(img);
}
/* set tooltip if we have; it is actually a comment from .desktop file */
mi[pos].tooltip((*ds)->get_comment());
}
}
@ -973,11 +986,11 @@ static unsigned int construct_edelib_menu(MenuContextList &lst, MenuItem *mi, un
mi[pos].flags = 0;
mi[pos].shortcut_ = 0;
mi[pos].image(NULL);
mi[pos].labeltype_ = FL_NORMAL_LABEL;
mi[pos].labelfont_ = FL_HELVETICA;
mi[pos].labelsize_ = FL_NORMAL_SIZE;
mi[pos].labelcolor_ = FL_BLACK;
MenuItem::init_extensions(&mi[pos]);
/* set callback and callback data to be current entry */
mi[pos].callback_ = logout_cb;
@ -993,7 +1006,7 @@ static unsigned int construct_edelib_menu(MenuContextList &lst, MenuItem *mi, un
/* end this menu */
mi[pos].text = NULL;
mi[pos].image(NULL);
MenuItem::init_extensions(&mi[pos]);
//E_DEBUG("{0}\n");
@ -1006,33 +1019,60 @@ static unsigned int construct_edelib_menu(MenuContextList &lst, MenuItem *mi, un
return pos;
}
MenuItem *xdg_menu_load(void) {
/* assure they are empty */
E_RETURN_VAL_IF_FAIL(global_parse_list.empty() == true, NULL);
E_RETURN_VAL_IF_FAIL(global_context_list.empty() == true, NULL);
void xdg_menu_applications_location(StrList &lst) {
lst.clear();
if(system_data_dirs(lst) < 1)
return;
StrListIt it = lst.begin(), it_end = lst.end();
for(; it != it_end; ++it)
*it = build_filename(it->c_str(), "applications");
/*
* Add user directory too; the spec is unclear about this, but official menu spec tests
* requires it. Also, users will be able to add menu items without superuser permissions.
*/
String user_dir = user_data_dir();
lst.push_back(build_filename(user_dir.c_str(), "applications"));
}
XdgMenuContent *xdg_menu_load(void) {
XdgMenuContent *content = new XdgMenuContent();
/* load everything */
menu_all_parse_lists_load(global_parse_list, global_context_list);
menu_all_parse_lists_load(content->parse_list, content->context_list);
unsigned int sz = menu_context_list_count(global_context_list);
unsigned int sz = menu_context_list_count(content->context_list);
E_RETURN_VAL_IF_FAIL(sz > 0, NULL);
MenuItem *mi = new MenuItem[sz + 2]; /* plus logout + ending NULL */
unsigned int pos = construct_edelib_menu(global_context_list, mi, 0);
unsigned int pos = construct_edelib_menu(content->context_list, mi, 0);
mi[pos].text = NULL;
/*
* MenuItem does not have constructor, so everywhere where we access MenuItem object, image
* member must be NULL-ed too
*/
mi[pos].image(NULL);
MenuItem::init_extensions(&mi[pos]);
E_ASSERT(pos <= sz + 2);
return mi;
content->fltk_menu = mi;
return content;
}
void xdg_menu_delete(MenuItem *m) {
delete [] m;
menu_all_parse_lists_clear(global_parse_list, global_context_list);
void xdg_menu_delete(XdgMenuContent *m) {
E_RETURN_IF_FAIL(m != NULL);
delete [] m->fltk_menu;
menu_all_parse_lists_clear(m->parse_list, m->context_list);
delete m;
}
MenuItem *xdg_menu_to_fltk_menu(XdgMenuContent *m) {
E_RETURN_VAL_IF_FAIL(m != NULL, NULL);
return m->fltk_menu;
}

View File

@ -1,13 +1,45 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __XDGMENUREADER_H__
#define __XDGMENUREADER_H__
#include <edelib/MenuItem.h>
#include <edelib/List.h>
#include <edelib/String.h>
EDELIB_NS_USING(MenuItem)
EDELIB_NS_USING(String)
EDELIB_NS_USING(list)
typedef list<String> StrList;
typedef list<String>::iterator StrListIt;
void xdg_menu_dump_for_test_suite(void);
/* all locations where menu files are stored */
void xdg_menu_applications_location(StrList &lst);
MenuItem *xdg_menu_load(void);
void xdg_menu_delete(MenuItem *it);
struct XdgMenuContent;
XdgMenuContent *xdg_menu_load(void);
void xdg_menu_delete(XdgMenuContent *c);
MenuItem *xdg_menu_to_fltk_menu(XdgMenuContent *c);
#endif

View File

@ -4,7 +4,6 @@
#include <FL/Fl_Window.H>
#include <edelib/Debug.h>
#include "Applet.h"
#include "Panel.h"
#include "Tray.h"
@ -45,6 +44,7 @@ static int handle_xevent(int e) {
}
} else if(fl_xevent->type == DestroyNotify) {
XDestroyWindowEvent xev = fl_xevent->xdestroywindow;
E_DEBUG(E_STRLOC ": Unock request for %i\n", fl_xevent->xclient.data.l[2]);
curr_tray->unembed_window(xev.window);
return false;
} else if(fl_xevent->type == ConfigureNotify) {
@ -88,6 +88,7 @@ void Tray::distribute_children(void) {
Y = y();
for(int i = 0; i < children(); i++) {
child(i)->position(X, Y);
E_DEBUG(E_STRLOC ": child %i at %i %i\n", i, child(i)->x(), child(i)->y());
X += child(i)->w() + TRAY_ICONS_SPACE;
}
}
@ -203,7 +204,8 @@ void Tray::add_to_tray(Fl_Widget *win) {
w(w() + win->w() + TRAY_ICONS_SPACE);
distribute_children();
redraw();
//redraw();
EDE_PANEL_GET_PANEL_OBJECT(this)->relayout();
}
@ -211,10 +213,13 @@ void Tray::remove_from_tray(Fl_Widget *win) {
remove(win);
w(w() - win->w() - TRAY_ICONS_SPACE);
win->hide();
delete win;
distribute_children();
redraw();
EDE_PANEL_GET_PANEL_OBJECT(this)->relayout();
EDE_PANEL_GET_PANEL_OBJECT(this)->redraw();
}
int Tray::handle(int e) {

View File

@ -4,6 +4,7 @@
#include <FL/Fl_Group.H>
#include <FL/x.H>
#include <edelib/List.h>
#include "Applet.h"
EDELIB_NS_USING(list)

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdlib.h>
#include <FL/Fl.H>
@ -24,10 +44,12 @@ EDELIB_NS_USING(IconLoader)
EDELIB_NS_USING(ICON_SIZE_TINY)
EDELIB_NS_USING(netwm_window_close)
EDELIB_NS_USING(netwm_window_set_active)
EDELIB_NS_USING(netwm_window_maximize)
EDELIB_NS_USING(netwm_window_get_title)
EDELIB_NS_USING(wm_window_ede_restore)
EDELIB_NS_USING(wm_window_get_state)
EDELIB_NS_USING(netwm_window_get_icon)
EDELIB_NS_USING(netwm_window_set_state)
EDELIB_NS_USING(NETWM_STATE_ACTION_TOGGLE)
EDELIB_NS_USING(NETWM_STATE_MAXIMIZED)
EDELIB_NS_USING(wm_window_set_state)
EDELIB_NS_USING(WM_WINDOW_STATE_ICONIC)
@ -60,32 +82,32 @@ static void close_cb(Fl_Widget*, void *b) {
static void restore_cb(Fl_Widget*, void *b) {
TaskButton *bb = (TaskButton*)b;
wm_window_ede_restore(bb->get_window_xid());
netwm_window_set_active(bb->get_window_xid());
netwm_window_set_active(bb->get_window_xid(), 1);
redraw_whole_panel(bb);
}
static void minimize_cb(Fl_Widget*, void *b) {
TaskButton *bb = (TaskButton*)b;
if(wm_window_get_state(bb->get_window_xid()) != WM_WINDOW_STATE_ICONIC)
wm_window_set_state(bb->get_window_xid(), WM_WINDOW_STATE_ICONIC);
redraw_whole_panel(bb);
/* WM_WINDOW_STATE_ICONIC is safer on other window managers than NETWM_STATE_HIDDEN */
wm_window_set_state(bb->get_window_xid(), WM_WINDOW_STATE_ICONIC);
}
static void maximize_cb(Fl_Widget*, void *b) {
TaskButton *bb = (TaskButton*)b;
netwm_window_set_active(bb->get_window_xid());
netwm_window_maximize(bb->get_window_xid());
netwm_window_set_active(bb->get_window_xid(), 1);
netwm_window_set_state(bb->get_window_xid(), NETWM_STATE_MAXIMIZED, NETWM_STATE_ACTION_TOGGLE);
redraw_whole_panel(bb);
}
TaskButton::TaskButton(int X, int Y, int W, int H, const char *l) : Fl_Button(X, Y, W, H, l), xid(0), image_alloc(false) {
TaskButton::TaskButton(int X, int Y, int W, int H, const char *l) : Fl_Button(X, Y, W, H, l),
xid(0), wspace(0), old_value(0), image_alloc(false), dragged(false), net_wm_icon(0)
{
box(FL_UP_BOX);
align(FL_ALIGN_INSIDE | FL_ALIGN_LEFT | FL_ALIGN_CLIP);
if(IconLoader::inited()) {
@ -181,64 +203,13 @@ void TaskButton::update_title_from_xid(void) {
}
}
/* stolen from pekwm */
void TaskButton::update_image_from_xid(void) {
E_RETURN_IF_FAIL(xid >= 0);
Atom real;
int format;
unsigned long n, extra;
unsigned char *prop = 0;
long len = 2;
int status = XGetWindowProperty(fl_display, xid,
net_wm_icon , 0L, len, False, XA_CARDINAL, &real, &format, &n, &extra, (unsigned char**)&prop);
if((status != Success) || (real != XA_CARDINAL)) {
if(prop) XFree(prop);
return;
}
long *data = (long*)prop;
unsigned int width, height;
width = data[0];
height = data[1];
XFree(prop);
len += width * height;
format = 0;
prop = 0;
real = 0;
status = XGetWindowProperty(fl_display, xid,
net_wm_icon , 0L, len, False, XA_CARDINAL, &real, &format, &n, &extra, (unsigned char**)&prop);
if((status != Success) || (real != XA_CARDINAL)) {
if(prop) XFree(prop);
return;
}
data = (long*)prop;
unsigned char *img_data = new unsigned char[width * height * 4];
unsigned char *ptr = img_data;
int pixel;
for(int i = 2; i < len; i++) {
pixel = data[i];
*ptr++ = pixel >> 16 & 0xff;
*ptr++ = pixel >> 8 & 0xff;
*ptr++ = pixel & 0xff;
*ptr++ = pixel >> 24 & 0xff;
}
XFree(prop);
Fl_RGB_Image *img = new Fl_RGB_Image(img_data, width, height, 4);
img->alloc_array = 1;
Fl_RGB_Image *img = netwm_window_get_icon(xid, TASKBUTTON_ICON_W);
if(!img) return;
int width = img->w(), height = img->h();
/* some safety, scale it if needed */
if((width > TASKBUTTON_ICON_W) || (height > TASKBUTTON_ICON_H)) {
@ -256,3 +227,30 @@ void TaskButton::update_image_from_xid(void) {
image(img);
image_alloc = true;
}
int TaskButton::handle(int e) {
switch(e) {
case FL_PUSH:
/*
* Remember old value, as value() result affect will box be drawn as FL_UP_BOX or FL_DOWN_BOX.
* This trick should return box to the old state in case of dragging.
*/
old_value = value();
return Fl_Button::handle(e);
case FL_DRAG:
dragged = true;
return 1;
case FL_RELEASE:
if(dragged) {
Taskbar *taskbar = (Taskbar*)parent();
taskbar->try_dnd(this, Fl::event_x(), Fl::event_y());
dragged = false;
value(old_value);
return 1;
}
/* fallthrough */
}
return Fl_Button::handle(e);
}

View File

@ -1,3 +1,23 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __TASKBUTTON_H__
#define __TASKBUTTON_H__
@ -8,11 +28,13 @@ class TaskButton : public Fl_Button {
private:
/* window ID this button handles */
Window xid;
int wspace;
char old_value; /* for storing value() as it affects boxtype */
bool image_alloc;
bool dragged;
Atom net_wm_icon;
void clear_image(void);
public:
TaskButton(int X, int Y, int W, int H, const char *l = 0);
~TaskButton();
@ -25,6 +47,11 @@ public:
void update_title_from_xid(void);
void update_image_from_xid(void);
void set_workspace(int s) { wspace = s; }
int get_workspace(void) { return wspace; }
int handle(int e);
};
#endif

View File

@ -1,4 +1,22 @@
#include "Applet.h"
/*
* $Id$
*
* Copyright (C) 2012-2014 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <FL/Fl.H>
#include <FL/Fl_Button.H>
@ -7,7 +25,6 @@
#include "TaskButton.h"
#include "Taskbar.h"
#include "Panel.h"
#define DEFAULT_CHILD_W 175
#define DEFAULT_SPACING 5
@ -19,6 +36,7 @@ EDELIB_NS_USING(netwm_window_is_manageable)
EDELIB_NS_USING(netwm_window_get_workspace)
EDELIB_NS_USING(netwm_window_get_active)
EDELIB_NS_USING(netwm_window_set_active)
EDELIB_NS_USING(netwm_window_set_state)
EDELIB_NS_USING(netwm_workspace_get_current)
EDELIB_NS_USING(wm_window_set_state)
EDELIB_NS_USING(wm_window_get_state)
@ -27,7 +45,10 @@ EDELIB_NS_USING(NETWM_CHANGED_CURRENT_WORKSPACE)
EDELIB_NS_USING(NETWM_CHANGED_WINDOW_LIST)
EDELIB_NS_USING(NETWM_CHANGED_WINDOW_NAME)
EDELIB_NS_USING(NETWM_CHANGED_WINDOW_ICON)
EDELIB_NS_USING(NETWM_CHANGED_WINDOW_DESKTOP)
EDELIB_NS_USING(WM_WINDOW_STATE_ICONIC)
EDELIB_NS_USING(NETWM_STATE_ACTION_TOGGLE)
EDELIB_NS_USING(NETWM_STATE_HIDDEN)
static void button_cb(TaskButton *b, void *t) {
Taskbar *tt = (Taskbar*)t;
@ -40,10 +61,23 @@ static void button_cb(TaskButton *b, void *t) {
static void net_event_cb(int action, Window xid, void *data) {
E_RETURN_IF_FAIL(data != NULL);
if(action == NETWM_CHANGED_CURRENT_WORKSPACE || action == NETWM_CHANGED_WINDOW_LIST) {
/* this is a message, so property is not changed and netwm_window_get_active() must be called */
if(action == NETWM_CHANGED_ACTIVE_WINDOW) {
Taskbar *tt = (Taskbar*)data;
tt->create_task_buttons();
tt->update_active_button();
return;
}
if(action == NETWM_CHANGED_CURRENT_WORKSPACE) {
Taskbar *tt = (Taskbar*)data;
tt->update_workspace_change();
return;
}
if(action == NETWM_CHANGED_WINDOW_LIST) {
Taskbar *tt = (Taskbar*)data;
tt->update_task_buttons();
return;
}
@ -53,25 +87,27 @@ static void net_event_cb(int action, Window xid, void *data) {
return;
}
/* this is a message, so property is not changed and netwm_window_get_active() must be called */
if(action == NETWM_CHANGED_ACTIVE_WINDOW) {
Taskbar *tt = (Taskbar*)data;
tt->update_active_button();
return;
}
if(action == NETWM_CHANGED_WINDOW_ICON) {
Taskbar *tt = (Taskbar*)data;
tt->update_child_icon(xid);
return;
}
if(action == NETWM_CHANGED_WINDOW_DESKTOP) {
Taskbar *tt = (Taskbar*)data;
tt->update_child_workspace(xid);
return;
}
}
Taskbar::Taskbar() : Fl_Group(0, 0, 40, 25), curr_active(NULL), prev_active(NULL), panel(NULL) {
Taskbar::Taskbar() : WidgetGroup(0, 0, 40, 25), curr_active(NULL), prev_active(NULL) {
end();
fixed_layout = false;
ignore_workspace_value = false;
panel = EDE_PANEL_GET_PANEL_OBJECT(this);
create_task_buttons();
current_workspace = netwm_workspace_get_current();
update_task_buttons();
netwm_callback_add(net_event_cb, this);
}
@ -79,64 +115,124 @@ Taskbar::~Taskbar() {
netwm_callback_remove(net_event_cb);
}
void Taskbar::create_task_buttons(void) {
/* erase all current elements */
if(children())
clear();
void Taskbar::configure(Resource *res) {
E_RETURN_IF_FAIL(res != NULL);
res->get("Taskbar", "fixed_layout", fixed_layout, false);
res->get("Taskbar", "all_desktops", ignore_workspace_value, false);
/* also current/prev storage */
curr_active = prev_active = NULL;
if(visible()) update_task_buttons();
}
/* redraw it, in case no windows exists in this workspace */
panel_redraw();
void Taskbar::update_task_buttons(void) {
Window *wins;
int ws, nwins = netwm_window_get_all_mapped(&wins);
Window *wins, transient_prop_win;
int nwins = netwm_window_get_all_mapped(&wins);
if(nwins < 1) {
if(children() > 0) clear();
return;
}
TaskButton *b;
bool need_full_redraw = false;
for(int i = 0, found; i < children(); i++) {
found = 0;
b = (TaskButton*)child(i);
if(nwins > 0) {
TaskButton *b;
int curr_workspace = netwm_workspace_get_current();
for(int j = 0; j < nwins; j++) {
if(b->get_window_xid() == wins[j]) {
/* assure this window is on current workspace */
found = 1;
break;
}
}
for(int i = 0; i < nwins; i++) {
transient_prop_win = None;
if(!found) {
/* FLTK since 1.3 optimized Fl_Group::remove() */
#if (FL_MAJOR_VERSION >= 1) && (FL_MINOR_VERSION >= 3)
remove(i);
#else
remove(b);
#endif
/* Fl_Group does not call delete on remove() */
delete b;
need_full_redraw = true;
}
}
if(!netwm_window_is_manageable(wins[i]))
continue;
/* now see which one needs to be created */
for(int i = 0, found; i < nwins; i++) {
found = 0;
/*
* see if it has WM_TRANSIENT_FOR hint set; transient_prop_win would point to parent window, but
* parent should not be root window for this screen
*/
if(XGetTransientForHint(fl_display, wins[i], &transient_prop_win)
&& (transient_prop_win != None)
&& (transient_prop_win != RootWindow(fl_display, fl_screen)))
{
continue;
}
for(int j = 0; j < children(); j++) {
b = (TaskButton*)child(j);
/*
* show window per workspace
* TODO: allow showing all windows in each workspace
*/
if(curr_workspace == netwm_window_get_workspace(wins[i])) {
b = new TaskButton(0, 0, DEFAULT_CHILD_W, 25);
b->set_window_xid(wins[i]);
b->update_title_from_xid();
b->update_image_from_xid();
/* catch the name changes */
XSelectInput(fl_display, wins[i], PropertyChangeMask | StructureNotifyMask);
b->callback((Fl_Callback*)button_cb, this);
add(b);
if(b->get_window_xid() == wins[i]) {
found = 1;
break;
}
}
XFree(wins);
if(found || !netwm_window_is_manageable(wins[i]))
continue;
Window transient_prop_win = None;
/*
* see if it has WM_TRANSIENT_FOR hint set; transient_prop_win would point to parent window, but
* parent should not be root window for this screen
*/
if(XGetTransientForHint(fl_display, wins[i], &transient_prop_win)
&& (transient_prop_win != None)
&& (transient_prop_win != RootWindow(fl_display, fl_screen)))
{
continue;
}
/* create button */
ws = netwm_window_get_workspace(wins[i]);
b = new TaskButton(0, 0, DEFAULT_CHILD_W, 25);
b->set_window_xid(wins[i]);
b->update_title_from_xid();
b->update_image_from_xid();
b->set_workspace(ws);
/* mark it hidden by default */
b->hide();
/* catch the name changes */
XSelectInput(fl_display, wins[i], PropertyChangeMask | StructureNotifyMask);
b->callback((Fl_Callback*)button_cb, this);
/* add it to our list */
add(b);
if(visible_on_current_workspace(ws)) {
//need_full_redraw = true;
b->show();
}
}
XFree(wins);
layout_children();
update_active_button();
update_active_button(!need_full_redraw);
if(need_full_redraw) panel_redraw();
}
void Taskbar::update_workspace_change(void) {
if(!children()) return;
current_workspace = netwm_workspace_get_current();
TaskButton *b;
for(int i = 0; i < children(); i++) {
b = (TaskButton*)child(i);
visible_on_current_workspace(b->get_workspace()) ? b->show() : b->hide();
}
layout_children();
redraw();
}
void Taskbar::resize(int X, int Y, int W, int H) {
@ -145,37 +241,50 @@ void Taskbar::resize(int X, int Y, int W, int H) {
}
void Taskbar::layout_children(void) {
if(!children())
return;
if(!children()) return;
Fl_Widget *o;
int X = x() + Fl::box_dx(box());
int Y = y() + Fl::box_dy(box());
int W = w() - Fl::box_dw(box());
int X, Y, W, child_h, reduce = 0, sz = 0, all_buttons_w = 0;
int child_w = DEFAULT_CHILD_W;
int sz = children();
int all_buttons_w = 0;
X = x() + Fl::box_dx(box());
Y = y() + Fl::box_dy(box());
W = w() - Fl::box_dw(box());
child_h = parent()->h() - 10; /* same sizes as in panel */
/* figure out the bounds */
for(int i = 0; i < sz; i++)
all_buttons_w += child(i)->w() + DEFAULT_SPACING;
for(int i = 0; i < children(); i++) {
o = child(i);
if(!o->visible()) continue;
if(all_buttons_w > W) {
int reduce = (all_buttons_w - W) / sz;
child_w -= reduce;
sz++;
/* resize every child to default size so we can calculate total length */
o->resize(o->x(), o->y(), (fixed_layout ? DEFAULT_CHILD_W : W), child_h);
all_buttons_w += o->w();
/* do not include ending spaces */
if(i != children() - 1)
all_buttons_w += DEFAULT_SPACING;
}
/* now, position each child and resize it if needed */
for(int i = 0; i < sz; i++) {
o = child(i);
/* find reduction size */
if(all_buttons_w > W)
reduce = (all_buttons_w - W) / sz;
o->resize(X, Y, child_w, o->h());
/* now, position each child and resize it if needed */
for(int i = 0; i < children(); i++) {
o = child(i);
if(!o->visible()) continue;
/*
* I'm putting -1 here to leave a small space at the end of group; this will also
* make children adaptive to not overflow group in case too many of them was created
*/
o->resize(X, Y, o->w() - reduce - 1, child_h);
X += o->w() + DEFAULT_SPACING;
}
}
void Taskbar::update_active_button(int xid) {
void Taskbar::update_active_button(bool do_redraw, int xid) {
if(!children())
return;
@ -187,14 +296,17 @@ void Taskbar::update_active_button(int xid) {
TaskButton *o;
for(int i = 0; i < children(); i++) {
o = (TaskButton*)child(i);
if(!o->visible()) continue;
if(o->get_window_xid() == (Window)xid)
if(o->get_window_xid() == (Window)xid) {
o->box(FL_DOWN_BOX);
else
curr_active = o;
} else {
o->box(FL_UP_BOX);
}
}
redraw();
if(do_redraw) redraw();
}
void Taskbar::activate_window(TaskButton *b) {
@ -210,6 +322,7 @@ void Taskbar::activate_window(TaskButton *b) {
if(prev_active &&
prev_active != b &&
prev_active->get_workspace() == b->get_workspace() &&
wm_window_get_state(prev_active->get_window_xid()) != WM_WINDOW_STATE_ICONIC)
{
xid = prev_active->get_window_xid();
@ -221,10 +334,9 @@ void Taskbar::activate_window(TaskButton *b) {
}
/* active or restore minimized */
netwm_window_set_active(xid);
update_active_button(xid);
netwm_window_set_active(xid, 1);
update_active_button(false, xid);
/* TODO: use stack for this (case when this can't handle: minimize three window, out of four on the workspace) */
prev_active = curr_active;
curr_active = b;
}
@ -236,7 +348,7 @@ void Taskbar::update_child_title(Window xid) {
for(int i = 0; i < children(); i++) {
o = (TaskButton*)child(i);
if(o->get_window_xid() == xid) {
if(o->visible() && o->get_window_xid() == xid) {
o->update_title_from_xid();
break;
}
@ -250,7 +362,7 @@ void Taskbar::update_child_icon(Window xid) {
for(int i = 0; i < children(); i++) {
o = (TaskButton*)child(i);
if(o->get_window_xid() == xid) {
if(o->visible() && o->get_window_xid() == xid) {
o->update_image_from_xid();
o->redraw();
break;
@ -258,11 +370,71 @@ void Taskbar::update_child_icon(Window xid) {
}
}
void Taskbar::panel_redraw(void) {
E_RETURN_IF_FAIL(panel != NULL);
panel->redraw();
void Taskbar::update_child_workspace(Window xid) {
if(!children()) return;
TaskButton *o;
for(int i = 0; i < children(); i++) {
o = (TaskButton*)child(i);
if(o->get_window_xid() == xid) {
int ws = netwm_window_get_workspace(xid);
o->set_workspace(ws);
visible_on_current_workspace(ws) ? o->show() : o->hide();
break;
}
}
layout_children();
redraw();
}
void Taskbar::panel_redraw(void) {
parent()->redraw();
}
void Taskbar::try_dnd(TaskButton *b, int xpos, int ypos) {
if(!children()) return;
/*
* try to find position of incoming child, as the child, when is moved
* forward, has to go on 'target_pos + 1' instead only 'target_pos'
*/
int child_pos = find(b);
E_RETURN_IF_FAIL(child_pos != children());
TaskButton *o;
for(int i = 0; i < children(); i++) {
o = (TaskButton*)child(i);
if(o == b) continue;
if((xpos > b->x() && xpos < b->x() + b->w()) &&
(ypos > b->y() && ypos < b->y() + b->h()))
{
/* not moved outside child range */
return;
}
if((xpos > o->x() && xpos < o->x() + o->w()) &&
(ypos > o->y() && ypos < o->y() + o->h()))
{
/* Try to find widget position in array. Widgets in array are not sorted in any order. */
int pos = find(o);
if(pos == children()) {
/* not found, proceed with the search */
continue;
}
/* increase just in case target position is in front */
pos += (pos > child_pos) ? 1 : 0;
insert(*b, pos);
break;
}
}
layout_children();
redraw();
}
EDE_PANEL_APPLET_EXPORT (
Taskbar,

View File

@ -1,31 +1,71 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __TASKBAR_H__
#define __TASKBAR_H__
#include <FL/Fl_Group.H>
#include <edelib/Resource.h>
#include "Applet.h"
EDELIB_NS_USING(Resource)
/* if button should be on visible on all workspaces */
#define ALL_WORKSPACES -1
class TaskButton;
class Panel;
typedef AppletWidget<Fl_Group> WidgetGroup;
class Taskbar : public Fl_Group {
class Taskbar : public WidgetGroup {
public:
TaskButton *curr_active, *prev_active;
Panel *panel;
bool fixed_layout; /* fixed or streched layout of buttons */
bool ignore_workspace_value; /* should all windows be shown ignoring workspace value */
int current_workspace;
bool visible_on_current_workspace(int ws) {
return (ignore_workspace_value == true) || (ws == ALL_WORKSPACES) || (ws == current_workspace);
}
public:
Taskbar();
~Taskbar();
void configure(Resource *res);
void create_task_buttons(void);
void update_task_buttons(void);
void update_workspace_change(void);
void resize(int X, int Y, int W, int H);
void layout_children(void);
void update_active_button(int xid = -1);
void update_active_button(bool do_redraw = true, int xid = -1);
void activate_window(TaskButton *b);
void update_child_title(Window xid);
void update_child_icon(Window xid);
void update_child_workspace(Window xid);
void panel_redraw(void);
/* try to move child on place of other child, but only if it falls within x,y range */
void try_dnd(TaskButton *b, int x, int y);
};
#endif

View File

@ -1,38 +1,48 @@
/*
* $Id$
*
* Copyright (C) 2012 Sanel Zukan
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <signal.h>
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Button.H>
#include <edelib/Ede.h>
#include "Panel.h"
#include "AppletManager.h"
static bool running;
static Panel *panel;
static void exit_signal(int signum) {
running = false;
if(panel) panel->hide();
}
int main(int argc, char **argv) {
EDE_APPLICATION("ede-panel");
panel = NULL;
signal(SIGTERM, exit_signal);
signal(SIGKILL, exit_signal);
signal(SIGINT, exit_signal);
Panel *panel = new Panel();
panel->load_applets();
panel = new Panel();
panel->show();
running = true;
while(running)
Fl::wait();
/* so Panel::hide() can be called */
panel->hide();
return 0;
return Fl::run();
}

View File

@ -40,7 +40,9 @@ static KnownApp app_filemanagers[] = {
static KnownApp app_terminals[] = {
{"X11 terminal", "xterm"},
{"Rxvt", "rxvt"},
{"Rxvt Unicode", "urxvt"},
{"Mrxvt", "mrxvt"},
{"Small Terminal", "st"},
{"Xfce Terminal", "xfterm4"},
{"GNOME Terminal", "gnome-terminal"},
KNOWN_APP_END

View File

@ -43,6 +43,10 @@ static Fl_Spinner* timeout_val;
static Fl_Double_Window* main_win;
static Fl_Double_Window* preview_win;
static bool hacks_sorter(SaverHack* const& a, SaverHack* const& b) {
return a->name < b->name;
}
static void dpms_enable_cb(Fl_Widget* w, void* s) {
Fl_Check_Button* o = (Fl_Check_Button*)w;
SaverPrefs* sp = (SaverPrefs*)s;
@ -170,6 +174,7 @@ int main(int argc, char **argv) {
if(sp->curr_hack >= sp->hacks.size())
sp->curr_hack = 0;
sp->hacks.sort(hacks_sorter);
HackListIter it = sp->hacks.begin(), it_end = sp->hacks.end();
for(int i = 1; it != it_end; ++it, i++) {
saver_list->add((*it)->name.c_str(), 0, 0);

View File

@ -74,6 +74,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/param.h>
#include <stdio.h>

View File

@ -215,12 +215,11 @@ int main(int argc, char **argv) {
Fl_Button* close_button = new Fl_Button(435, 224, 90, 25, _("&Close"));
close_button->callback(close_cb);
// check_button somehow steal focus
close_button->take_focus();
win->end();
window_center_on_screen(win);
win->show(argc, argv);
// check_button somehow steal focus
close_button->take_focus();
Fl::run();

View File

@ -1,24 +0,0 @@
#
# $Id$
#
# Part of Equinox Desktop Environment (EDE).
# Copyright (c) 2008 EDE Authors.
#
# This program is licensed under the terms of the
# GNU General Public License version 2 or later.
# See COPYING for the details.
SubDir TOP emountd ;
SOURCE = emountd.cpp ;
ObjectC++Flags $(SOURCE) : -Wno-long-long
# libhal have a bug that fails on C++ with '-pedantic' flag
[ RemoveFlag -pedantic : $(GLOBALFLAGS) ]
$(EDELIBINCLUDE)
$(HALINCLUDE) ;
Main emountd : $(SOURCE) ;
LinkAgainst emountd : $(EDELIBLIB) $(HALLIB) $(STDLIB) $(LIBM) ;
InstallEdeProgram emountd ;
EdeManual emountd.txt ;

View File

@ -1,469 +0,0 @@
/*
* $Id$
*
* emountd, mount/unmount notifier
* Part of Equinox Desktop Environment (EDE).
* Copyright (c) 2008 Sanel Zukan <karijes@equinox-project.org>
*
* This program is licensed under the terms of the
* GNU General Public License version 2 or later.
* See COPYING for the details.
*/
/*
* A bunch of this code is inspired from Thunar (http://thunar.xfce.org)
* since HAL documentation pretty sucks.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#ifdef HAVE_HAL
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <libhal-storage.h>
#include <edelib/List.h>
#include <edelib/Missing.h>
/* HAL can return NULL as error message if not checked */
#define CHECK_STR(s) ((s != NULL) ? s : "<unknown>")
#define EMOUNTD_INTERFACE "org.equinoxproject.Emountd"
#define EMOUNTD_OBJECT_PATH "/org/equinoxproject/Emountd"
#define EDE_SHUTDOWN_INTERFACE "org.equinoxproject.Shutdown"
#define EDE_SHUTDOWN_MEMBER "Shutdown"
struct DeviceInfo {
unsigned int udi_hash;
const char* label;
const char* mount_point;
const char* device_file;
LibHalDriveType drive_type;
LibHalVolumeDiscType cdrom_type; /* Valid only if drive_type == LIBHAL_DRIVE_TYPE_CDROM */
int read_only;
};
/* audio CD are special */
struct DeviceAudioInfo {
unsigned int udi_hash;
const char* label;
const char* device_file;
};
typedef edelib::list<unsigned int> UIntList;
typedef edelib::list<unsigned int>::iterator UIntListIter;
static int quit_signaled = 0;
static DBusConnection* bus_connection = NULL;
static UIntList known_audio_udis;
void quit_signal(int sig) {
quit_signaled = 1;
}
/* A hash function from Dr.Dobbs Journal. */
unsigned int do_hash(const char* key, int keylen) {
unsigned hash ;
int i;
for (i = 0, hash = 0; i < keylen ;i++) {
hash += (long)key[i] ;
hash += (hash<<10);
hash ^= (hash>>6) ;
}
hash += (hash <<3);
hash ^= (hash >>11);
hash += (hash <<15);
return hash ;
}
void send_dbus_signal_mounted(DeviceInfo* info) {
int vi;
dbus_bool_t vb;
const char* vs;
DBusMessage* msg = dbus_message_new_signal(EMOUNTD_OBJECT_PATH, EMOUNTD_INTERFACE, "Mounted");
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
/* open sub-iterator */
DBusMessageIter sub;
dbus_message_iter_open_container(&it, DBUS_TYPE_STRUCT, NULL, &sub);
/* hash UDI is first member*/
dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &info->udi_hash);
vs = info->label;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vs = info->mount_point;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vs = info->device_file;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vb = (dbus_bool_t)info->read_only;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_BOOLEAN, &vb);
vi = (int)info->drive_type;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &vi);
vi = (int)info->cdrom_type;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_INT32, &vi);
/* close sub-iterator */
dbus_message_iter_close_container(&it, &sub);
dbus_uint32_t serial;
if(!dbus_connection_send(bus_connection, msg, &serial))
printf("Failed to send message (%i)\n", serial);
dbus_connection_flush(bus_connection);
dbus_message_unref(msg);
}
void send_dbus_signal_audio_cd_added(DeviceAudioInfo* info) {
const char* vs;
DBusMessage* msg = dbus_message_new_signal(EMOUNTD_OBJECT_PATH, EMOUNTD_INTERFACE, "AudioCDAdded");
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
/* open sub-iterator */
DBusMessageIter sub;
dbus_message_iter_open_container(&it, DBUS_TYPE_STRUCT, NULL, &sub);
/* hash UDI is first member*/
dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &info->udi_hash);
vs = info->label;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
vs = info->device_file;
dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &vs);
/* close sub-iterator */
dbus_message_iter_close_container(&it, &sub);
dbus_uint32_t serial;
if(!dbus_connection_send(bus_connection, msg, &serial))
printf("Failed to send message (%i)\n", serial);
dbus_connection_flush(bus_connection);
dbus_message_unref(msg);
}
void send_dbus_signal_removed(unsigned int udi_hash, int is_audio) {
const char* sig;
if(is_audio)
sig = "AudioCDRemoved";
else
sig = "Unmounted";
DBusMessage* msg = dbus_message_new_signal(EMOUNTD_OBJECT_PATH, EMOUNTD_INTERFACE, sig);
DBusMessageIter it;
dbus_message_iter_init_append(msg, &it);
dbus_message_iter_append_basic(&it, DBUS_TYPE_UINT32, &udi_hash);
dbus_uint32_t serial;
if(!dbus_connection_send(bus_connection, msg, &serial))
printf("Failed to send message (%i)\n", serial);
dbus_connection_flush(bus_connection);
dbus_message_unref(msg);
}
void device_info_init(DeviceInfo* i) {
i->udi_hash = 0;
i->label = 0;
i->mount_point = 0;
i->device_file = 0;
i->drive_type = (LibHalDriveType)-1; /* 0 is LIBHAL_DRIVE_TYPE_REMOVABLE_DISK */
i->cdrom_type = (LibHalVolumeDiscType)-1;
i->read_only = 0;
}
void device_audio_info_init(DeviceAudioInfo* i) {
i->udi_hash = 0;
i->label = 0;
i->device_file = 0;
}
void device_info_send(LibHalContext* ctx, const char* udi) {
/* spec said devices with this property should be ignored */
if(libhal_device_get_property_bool(ctx, udi, "volume.ignore", 0))
return;
/* check volume */
LibHalVolume* vol = libhal_volume_from_udi(ctx, udi);
if(!vol)
return;
/* determine udi of the drive this volume belongs to */
const char* drive_udi = libhal_volume_get_storage_device_udi(vol);
if(drive_udi) {
/* determine the drive for the volume */
LibHalDrive* drive = libhal_drive_from_udi(ctx, drive_udi);
if(drive) {
const char* label = libhal_device_get_property_string(ctx, udi, "volume.label", 0);
const char* dev = libhal_drive_get_device_file(drive);
unsigned int udi_hash = do_hash(udi, strlen(udi));
/* for audio CD's we send special signals */
if(libhal_volume_disc_has_audio(vol) && !libhal_volume_disc_has_data(vol)) {
DeviceAudioInfo d;
device_audio_info_init(&d);
d.udi_hash = udi_hash;
d.label = label;
d.device_file = dev;
/*
* register hash so when Audio CD is ejected (device_removed() will be called)
* we knows should we send AudioCDRemoved signal
*/
known_audio_udis.push_back(udi_hash);
/* send signal about Audio CD */
send_dbus_signal_audio_cd_added(&d);
} else {
/*
* Check if volume is mounted, since device_info_send() is called at emountd startup
* and collects known volumes. Also, this function is called from device_property_modified()
* and that will be when device mounts/unmounts. In either case, we send unmount signal
*/
if(!libhal_device_get_property_bool(ctx, udi, "volume.is_mounted", 0)) {
send_dbus_signal_removed(udi_hash, 0); /* TODO: or to send drive_udi? */
} else {
DeviceInfo d;
device_info_init(&d);
d.udi_hash = udi_hash;
d.label = label;
d.device_file = dev;
d.mount_point = libhal_device_get_property_string(ctx, udi, "volume.mount_point", 0);
d.read_only = (int)libhal_device_get_property_bool(ctx, udi, "volume.is_mounted_read_only", 0);
d.drive_type = libhal_drive_get_type(drive);
/* determine CD type if we got it */
if(d.drive_type == LIBHAL_DRIVE_TYPE_CDROM)
d.cdrom_type = libhal_volume_get_disc_type(vol);
/* send signal about mounted device*/
send_dbus_signal_mounted(&d);
libhal_free_string((char*)d.mount_point);
}
}
libhal_free_string((char*)label);
libhal_drive_free(drive);
}
}
libhal_volume_free(vol);
}
void device_added(LibHalContext* ctx, const char* udi) {
/* only used for Audio CD's */
device_info_send(ctx, udi);
}
void device_removed(LibHalContext* ctx, const char* udi) {
unsigned int udi_hash = do_hash(udi, strlen(udi));
/* signal audio CD removal if udi match ours */
UIntListIter it = known_audio_udis.begin(), it_end = known_audio_udis.end();
for(; it != it_end; ++it) {
if((*it) == udi_hash) {
send_dbus_signal_removed(udi_hash, 1);
known_audio_udis.erase(it);
break;
}
}
}
void device_property_modified(LibHalContext* ctx, const char* udi, const char* key, dbus_bool_t is_rem, dbus_bool_t is_added) {
/*
* we watch only 'volume.mount_point' property;
* it is always set after 'volue.is_mounted' property so we can check it manualy
*/
if(strcmp(key, "volume.mount_point") == 0)
device_info_send(ctx, udi);
}
#endif // HAVE_HAL
void help(void) {
puts("Usage: emountd [--no-daemon]");
puts("EDE mount/unmount notify manager");
}
int main(int argc, char** argv) {
int go_daemon = 1;
if(argc > 1) {
if(strcmp(argv[1], "--no-daemon") == 0)
go_daemon = 0;
else {
help();
return 1;
}
}
#ifndef HAVE_HAL
printf("HAL support not enabled!\n");
printf("Make sure you have system supporting HAL and installed HAL package and libraries\n");
printf("For more details, please visit: 'http://freedesktop.org/HAL'\n");
return 1;
#else
/* run in background */
if(go_daemon)
edelib_daemon(0, 0);
DBusError err;
DBusConnection* conn = NULL, *session_conn = NULL;
DBusMessage* down_msg = NULL;
LibHalContext* ctx = NULL;
LibHalDrive* hd;
char** drive_udis;
int n_drive_udis;
char** udis;
int n_udis;
signal(SIGINT, quit_signal);
signal(SIGTERM, quit_signal);
signal(SIGKILL, quit_signal);
signal(SIGQUIT, quit_signal);
ctx = libhal_ctx_new();
if(!ctx) {
puts("Unable to get libhal context");
goto error;
}
dbus_error_init(&err);
/* open system bus for HAL */
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
if(dbus_error_is_set(&err)) {
printf("Unable to connect to system bus %s : %s\n", err.name, err.message);
dbus_error_free(&err);
goto error;
}
/* open session bus for EDE */
session_conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
if(dbus_error_is_set(&err)) {
printf("Unable to connect to session bus %s : %s\n", err.name, err.message);
dbus_error_free(&err);
goto error;
}
bus_connection = session_conn;
/*
* make sure we are running only one instance; this is done by requesting ownership
* of the interface name
*/
if(dbus_bus_request_name(bus_connection, EMOUNTD_INTERFACE, 0, 0) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
printf("One instance of emountd is already running! Balling out...\n");
goto error;
}
/* let libhal use our system bus connection */
libhal_ctx_set_dbus_connection(ctx, conn);
if(!libhal_ctx_init(ctx, &err)) {
printf("Unable to init libhal context %s : %s\n", CHECK_STR(err.name), CHECK_STR(err.message));
printf("Does hald daemon is running?\n");
dbus_error_free(&err);
goto error;
}
libhal_ctx_set_device_added(ctx, device_added);
libhal_ctx_set_device_removed(ctx, device_removed);
libhal_ctx_set_device_property_modified(ctx, device_property_modified);
/* explicitly state to watch all properties or nothing will be received */
if(!libhal_device_property_watch_all(ctx, &err)) {
printf("Unable to watch properties %s : %s\n", CHECK_STR(err.name), CHECK_STR(err.message));
dbus_error_free(&err);
goto error;
}
/* now lookup storage devices already known by HAL */
drive_udis = libhal_find_device_by_capability(ctx, "storage", &n_drive_udis, &err);
if(drive_udis) {
for(int i = 0; i < n_drive_udis; i++) {
hd = libhal_drive_from_udi(ctx, drive_udis[i]);
if(!hd)
continue;
/* check for floppy since it does not have volumes */
if(libhal_drive_get_type(hd) == LIBHAL_DRIVE_TYPE_FLOPPY) {
device_info_send(ctx, drive_udis[i]);
} else {
/* determine all volumes for the given drive */
udis = libhal_drive_find_all_volumes(ctx, hd, &n_udis);
if(udis) {
for(int j = 0; j < n_udis; j++) {
device_info_send(ctx, udis[j]);
/* HAL bug #5279 */
free(udis[j]);
}
/* HAL bug #5279 */
free(udis);
}
}
libhal_drive_free(hd);
}
libhal_free_string_array(drive_udis);
}
/* add matcher for quit dbus signal */
dbus_bus_add_match(bus_connection, "type='signal',interface='"EDE_SHUTDOWN_INTERFACE"'", 0);
/*
* Now handle both system and session bus messages: system messages
* are to receive HAL notifications and bus messages are to dispatch them to EDE clients
* and to receive Shutdown signal
*/
while(1) {
if(quit_signaled)
break;
/* fetch and dispatch system bus messages */
dbus_connection_read_write_dispatch(conn, 10);
/* but only fetch session bus messages; they are processed here */
dbus_connection_read_write(bus_connection, 10);
down_msg = dbus_connection_pop_message(bus_connection);
if(down_msg && dbus_message_is_signal(down_msg, EDE_SHUTDOWN_INTERFACE, EDE_SHUTDOWN_MEMBER))
break;
sleep(1);
}
error:
if(!ctx)
libhal_ctx_free(ctx);
return 0;
#endif // HAVE_HAL
}

View File

@ -1,14 +0,0 @@
Emountd documentation
=====================
Emountd is EDE service responsible for reporting when storage
devices get mounted or unmounted. Reporting is done via D-BUS protocol and
interested applications should listen certain signals.
Specific emountd signals can be found at link:dbus-usage.html[D-BUS usage] page.
Options
-------
--no-daemon::
Do not run in background. Emountd will by default run in background.

View File

@ -26,8 +26,13 @@
#include <edelib/MessageBox.h>
#include <edelib/Nls.h>
#include <edelib/Run.h>
#include <FL/Fl.H>
#if EDELIB_HAVE_DBUS
#include <edelib/EdbusMessage.h>
#include <edelib/EdbusConnection.h>
#endif
#include "EvokeService.h"
#include "Splash.h"
@ -37,12 +42,6 @@
EDELIB_NS_USING(Config)
EDELIB_NS_USING(Resource)
EDELIB_NS_USING(EdbusMessage)
EDELIB_NS_USING(EdbusConnection)
EDELIB_NS_USING(EdbusError)
EDELIB_NS_USING(EDBUS_SESSION)
EDELIB_NS_USING(EDBUS_SYSTEM)
EDELIB_NS_USING(RES_SYS_ONLY)
EDELIB_NS_USING(file_remove)
EDELIB_NS_USING(file_test)
EDELIB_NS_USING(str_trim)
@ -51,16 +50,23 @@ EDELIB_NS_USING(alert)
EDELIB_NS_USING(ask)
EDELIB_NS_USING(FILE_TEST_IS_REGULAR)
#ifdef USE_LOCAL_CONFIG
# define CONFIG_GET_STRVAL(object, section, key, buff) object.get(section, key, buff, sizeof(buff))
#else
# define CONFIG_GET_STRVAL(object, section, key, buff) object.get(section, key, buff, sizeof(buff), RES_SYS_ONLY)
#if EDELIB_HAVE_DBUS
EDELIB_NS_USING(EdbusMessage)
EDELIB_NS_USING(EdbusConnection)
EDELIB_NS_USING(EdbusError)
EDELIB_NS_USING(EDBUS_SESSION)
EDELIB_NS_USING(EDBUS_SYSTEM)
#endif
#define CONFIG_GET_STRVAL(object, section, key, buff) object.get(section, key, buff, sizeof(buff))
/* stolen from xfce's xfsm-shutdown-helper */
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
# define POWEROFF_CMD "/sbin/shutdown -p now"
# define REBOOT_CMD "/sbin/shutdown -r now"
#elif defined(__OpenBSD__)
# define POWEROFF_CMD "/sbin/shutdown -hp now"
# define REBOOT_CMD "/sbin/shutdown -r now"
#elif defined(sun) || defined(__sun)
# define POWEROFF_CMD "/usr/sbin/shutdown -i 5 -g 0 -y"
# define REBOOT_CMD "/usr/sbin/shutdown -i 6 -g 0 -y"
@ -90,35 +96,46 @@ static int get_int_property_value(Atom at) {
}
static void send_dbus_ede_quit(void) {
#ifdef EDELIB_HAVE_DBUS
EdbusConnection c;
E_RETURN_IF_FAIL(c.connect(EDBUS_SESSION));
EdbusMessage msg;
msg.create_signal("/org/equinoxproject/Shutdown", "org.equinoxproject.Shutdown", "Shutdown");
c.send(msg);
#endif
}
static bool do_shutdown_or_restart(bool restart) {
#define CONSOLEKIT_SERVICE "org.freedesktop.ConsoleKit"
#define CONSOLEKIT_PATH "/org/freedesktop/ConsoleKit/Manager"
#define CONSOLEKIT_INTERFACE "org.freedesktop.ConsoleKit.Manager"
static bool do_shutdown_or_restart(bool restart, void (*x_shutdown_func)(void)) {
const char *action;
int r = 1;
#ifdef EDELIB_HAVE_DBUS
const char *can_do_action;
EdbusConnection c;
if(!c.connect(EDBUS_SYSTEM)) {
alert(_("Unable to connect to HAL daemon. Make sure both D-BUS and HAL daemons are running"));
alert(_("Unable to connect to DBus daemon. Make sure system DBus daemon is running and have permissions to access it"));
return false;
}
/* determine what to check first; ConsoleKit shutdown action calls 'Stop' */
action = restart ? "Restart" : "Stop";
can_do_action = restart ? "CanRestart" : "CanStop";
action = restart ? "Restart" : "Stop";
EdbusMessage msg, ret;
msg.create_method_call("org.freedesktop.ConsoleKit",
"/org/freedesktop/ConsoleKit/Manager",
"org.freedesktop.ConsoleKit.Manager",
action);
msg.create_method_call(CONSOLEKIT_SERVICE,
CONSOLEKIT_PATH,
CONSOLEKIT_INTERFACE,
can_do_action);
if(!c.send_with_reply_and_block(msg, 100, ret)) {
EdbusError *err = c.error();
alert(_("Unable to complete this action. Got '%s' (%s)"), err->name(), err->message());
alert(_("Unable to communicate with DBus properly. Got '%s' (%s)"), err->name(), err->message());
return false;
}
@ -128,25 +145,36 @@ static bool do_shutdown_or_restart(bool restart) {
}
EdbusMessage::iterator it = ret.begin();
if((*it).to_bool() == true)
return true;
if(it->is_bool() && it->to_bool() == true) {
/* first close all X children */
x_shutdown_func();
int r = ask(_("You are not allowed to execute this command. Please consult ConsoleKit documentation on how to allow privileged actions. "
"Would you like to try to execute system commands?"));
/* call action */
msg.create_method_call(CONSOLEKIT_SERVICE,
CONSOLEKIT_PATH,
CONSOLEKIT_INTERFACE,
action);
c.send(msg);
return true;
}
r = ask(_("You are not allowed to execute this command. Please consult ConsoleKit documentation on how to allow privileged actions. "
"Would you like to try to execute system commands?"));
#endif /* EDELIB_HAVE_DBUS */
/* try to do things manually */
if(!r) return false;
const char *cmd = _("restart");
action = _("restart");
if(restart) {
r = run_sync(REBOOT_CMD);
} else {
r = run_sync(POWEROFF_CMD);
cmd = _("shutdown");
action = _("shutdown");
}
if(r) {
alert(_("Unable to %s the computer. Probably you do not have enough permissions to do that"), cmd);
alert(_("Unable to %s the computer. Probably you do not have enough permissions to do that"), action);
return false;
}
@ -171,12 +199,11 @@ EvokeService* EvokeService::instance(void) {
}
bool EvokeService::setup_lock(const char* name) {
if(file_test(name, FILE_TEST_IS_REGULAR))
return false;
E_RETURN_VAL_IF_FAIL(file_test(name, FILE_TEST_IS_REGULAR) == false, false);
FILE* f = fopen(name, "w");
if(!f)
return false;
E_RETURN_VAL_IF_FAIL(f != NULL, false);
fclose(f);
lock_name = strdup(name);
@ -184,8 +211,7 @@ bool EvokeService::setup_lock(const char* name) {
}
void EvokeService::remove_lock(void) {
if(!lock_name)
return;
E_RETURN_IF_FAIL(lock_name != NULL);
file_remove(lock_name);
free(lock_name);
@ -193,14 +219,13 @@ void EvokeService::remove_lock(void) {
}
void EvokeService::clear_startup_items(void) {
if(startup_items.empty())
return;
E_RETURN_IF_FAIL(startup_items.size() > 0);
StartupItemListIter it = startup_items.begin(), it_end = startup_items.end();
for(; it != it_end; ++it)
StartupItemListIter it = startup_items.begin(), ite = startup_items.end();
while(it != ite) {
delete *it;
startup_items.clear();
it = startup_items.erase(it);
}
}
void EvokeService::read_startup(void) {
@ -221,40 +246,37 @@ void EvokeService::read_startup(void) {
return;
}
char tok_buff[256], buff[256];
char tokbuf[128], buf[128];
/* if nothing found, exit */
if(!CONFIG_GET_STRVAL(c, "Startup", "start_order", tok_buff))
return;
E_RETURN_IF_FAIL(CONFIG_GET_STRVAL(c, "Startup", "start_order", tokbuf));
if(CONFIG_GET_STRVAL(c, "Startup", "splash_theme", buff))
splash_theme = buff;
if(CONFIG_GET_STRVAL(c, "Startup", "splash_theme", buf))
splash_theme = buf;
for(const char* sect = strtok(tok_buff, ","); sect; sect = strtok(NULL, ",")) {
for(const char* sect = strtok(tokbuf, ","); sect; sect = strtok(NULL, ",")) {
/* remove leading/ending spaces, if exists */
str_trim(buff);
str_trim(buf);
/* assure each startup item has 'exec' key */
if(!CONFIG_GET_STRVAL(c, sect, "exec", buff)) {
if(!CONFIG_GET_STRVAL(c, sect, "exec", buf)) {
E_WARNING(E_STRLOC ": Startup item '%s' does not have anything to execute. Skipping...\n", sect);
continue;
}
StartupItem *s = new StartupItem;
s->exec = buff;
s->exec = buf;
if(CONFIG_GET_STRVAL(c, sect, "icon", buff))
s->icon = buff;
if(CONFIG_GET_STRVAL(c, sect, "description", buff))
s->description = buff;
if(CONFIG_GET_STRVAL(c, sect, "icon", buf))
s->icon = buf;
if(CONFIG_GET_STRVAL(c, sect, "description", buf))
s->description = buf;
startup_items.push_back(s);
}
}
void EvokeService::run_startup(bool splash, bool dryrun) {
if(startup_items.empty())
return;
E_RETURN_IF_FAIL(startup_items.size() > 0);
Splash s(startup_items, splash_theme, splash, dryrun);
s.run();
@ -265,7 +287,7 @@ void EvokeService::start_xsettings_manager(void) {
xsm = new Xsm;
if(Xsm::manager_running(fl_display, fl_screen)) {
int ret = edelib::ask(_("XSETTINGS manager already running on this screen. Would you like to replace it?"));
int ret = ask(_("XSETTINGS manager already running on this screen. Would you like to replace it?"));
if(ret < 1) {
stop_xsettings_manager(false);
return;
@ -273,19 +295,16 @@ void EvokeService::start_xsettings_manager(void) {
}
if(!xsm->init(fl_display, fl_screen)) {
edelib::alert(_("Unable to load XSETTINGS manager properly :-("));
alert(_("Unable to load XSETTINGS manager properly"));
stop_xsettings_manager(false);
}
E_RETURN_IF_FAIL(xsm);
if(xsm->load_serialized())
xsm->notify();
}
void EvokeService::stop_xsettings_manager(bool serialize) {
if(!xsm)
return;
E_RETURN_IF_FAIL(xsm != NULL);
if(serialize)
xsm->save_serialized();
@ -310,10 +329,12 @@ int EvokeService::handle(const XEvent* xev) {
if(xev->xproperty.atom == XA_EDE_EVOKE_SHUTDOWN_ALL) {
int val = get_int_property_value(XA_EDE_EVOKE_SHUTDOWN_ALL);
if(val == 1) {
int dw = DisplayWidth(fl_display, fl_screen);
int dh = DisplayHeight(fl_display, fl_screen);
int dw, dh, ret;
int ret = logout_dialog_show(dw, dh, LOGOUT_OPT_SHUTDOWN | LOGOUT_OPT_RESTART);
dw = DisplayWidth(fl_display, fl_screen);
dh = DisplayHeight(fl_display, fl_screen);
ret = logout_dialog_show(dw, dh, LOGOUT_OPT_SHUTDOWN | LOGOUT_OPT_RESTART);
if(ret == LOGOUT_RET_CANCEL)
return 1;
@ -321,12 +342,10 @@ int EvokeService::handle(const XEvent* xev) {
switch(ret) {
case LOGOUT_RET_RESTART:
if(!do_shutdown_or_restart(true))
return 1;
if(!do_shutdown_or_restart(true, x_shutdown)) return 1;
break;
case LOGOUT_RET_SHUTDOWN:
if(!do_shutdown_or_restart(false))
return 1;
if(!do_shutdown_or_restart(false, x_shutdown)) return 1;
break;
case LOGOUT_RET_LOGOUT:
default:

View File

@ -27,7 +27,7 @@ ObjectC++Flags Splash.cpp : -DEDEWM_HAVE_NET_SPLASH ;
ObjectC++Flags evoke.cpp : -DUSE_SIGHUP ;
ObjectC++Flags EvokeService.cpp : $(EDELIB_DBUS_INCLUDE) ;
LinkAgainstAsFirst evoke : $(EDELIB_DBUS_LIB) ;
LinkAgainstAsFirst evoke : $(EDELIB_DBUS_LIB) $(PTHREAD_LIBS) ;
EdeProgram evoke : $(SOURCE) ;

View File

@ -11,7 +11,7 @@
*/
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Return_Button.H>
#include <FL/Fl_Choice.H>
#include <FL/Fl.H>
#include <edelib/Window.h>
@ -78,7 +78,7 @@ int logout_dialog_show(int screen_w, int screen_h, int opt) {
c->value(0);
description->label(logout_options[0].opt_long);
Fl_Button* ok = new Fl_Button(140, 145, 90, 25, _("&OK"));
Fl_Return_Button* ok = new Fl_Return_Button(140, 145, 90, 25, _("&OK"));
ok->callback(ok_cb, c);
Fl_Button* cancel = new Fl_Button(235, 145, 90, 25, _("&Cancel"));
cancel->callback(cancel_cb);

View File

@ -10,7 +10,6 @@
* See COPYING for details.
*/
#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Shared_Image.H>
#include <edelib/Debug.h>
@ -20,6 +19,7 @@
#include <edelib/FileTest.h>
#include <edelib/Resource.h>
#include <edelib/Run.h>
#include <edelib/Netwm.h>
#include "Splash.h"
@ -31,8 +31,10 @@ EDELIB_NS_USING(Resource)
EDELIB_NS_USING(build_filename)
EDELIB_NS_USING(file_test)
EDELIB_NS_USING(run_async)
EDELIB_NS_USING(netwm_window_set_type)
EDELIB_NS_USING(RES_SYS_ONLY)
EDELIB_NS_USING(FILE_TEST_IS_DIR)
EDELIB_NS_USING(NETWM_WINDOW_TYPE_SPLASH)
#ifndef EDEWM_HAVE_NET_SPLASH
static Splash* global_splash = NULL;
@ -54,17 +56,10 @@ static int splash_xmessage_handler(int e) {
}
#endif
/*
* repeatedly call runner() until all clients are
* started then hide splash window
*/
/* repeatedly call runner() until all clients are started then hide splash window */
static void runner_cb(void* s) {
Splash* sp = (Splash*)s;
if(sp->next_client())
Fl::repeat_timeout(TIMEOUT_CONTINUE, runner_cb, sp);
else
sp->hide();
sp->next_client() ? Fl::repeat_timeout(TIMEOUT_CONTINUE, runner_cb, sp) : sp->hide();
}
Splash::Splash(StartupItemList& s, String& theme, bool show_it, bool dr) : Fl_Double_Window(480, 365) {
@ -77,46 +72,35 @@ Splash::Splash(StartupItemList& s, String& theme, bool show_it, bool dr) : Fl_Do
box(FL_BORDER_BOX);
}
Splash::~Splash() {
E_DEBUG(E_STRLOC ": Cleaning splash data\n");
/* elements of icons cleans Fl_Group */
delete [] icons;
Fl::remove_timeout(runner_cb);
}
/* after edewm got _NET_WM_WINDOW_TYPE_SPLASH support */
/* for wm's with _NET_WM_WINDOW_TYPE_SPLASH support */
#if EDEWM_HAVE_NET_SPLASH
void Splash::show(void) {
if(shown())
return;
if(shown()) return;
Fl_X::make_xid(this);
/*
* Edewm does not implement this for now. Alternative, working solution
* is used via register_top()/unregister_top(); also looks like later
* is working on othe wm's too.
*/
Atom win_type = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE", False);
Atom win_splash = XInternAtom(fl_display, "_NET_WM_WINDOW_TYPE_SPLASH", False);
XChangeProperty(fl_display, fl_xid(this), win_type, XA_ATOM, 32, PropModeReplace,
(unsigned char*)&win_splash, sizeof(Atom));
netwm_window_set_type(fl_xid(this), NETWM_WINDOW_TYPE_SPLASH);
}
#endif
void Splash::run(void) {
E_ASSERT(slist != NULL);
if(!show_splash) {
if(!show_splash || (splash_theme && (strcasecmp(splash_theme->c_str(), "none") == 0))) {
while(next_client_nosplash())
;
return;
}
fl_register_images();
String path, splash_theme_path;
#ifdef USE_LOCAL_CONFIG
@ -128,12 +112,12 @@ void Splash::run(void) {
return;
}
#endif
splash_theme_path += E_DIR_SEPARATOR;
splash_theme_path += *splash_theme;
if(!file_test(splash_theme_path.c_str(), FILE_TEST_IS_DIR)) {
E_WARNING(E_STRLOC ": Unable to locate '%s' in '%s' theme directory\n",
splash_theme->c_str(), splash_theme_path.c_str());
E_WARNING(E_STRLOC ": Unable to locate '%s' in '%s' theme directory\n", splash_theme->c_str(), splash_theme_path.c_str());
return;
}
@ -155,10 +139,7 @@ void Splash::run(void) {
bimg->image(splash_img);
}
/*
* place message box at the bottom with
* nice offset (10 px) from window borders
*/
/* place message box at the bottom with nice offset (10 px) from window borders */
msgbox = new Fl_Box(10, h() - 25 - 10, w() - 20, 25);
/*
@ -218,21 +199,18 @@ void Splash::run(void) {
clear_border();
/*
* If set_override() is used, message boxes will be
* popped behind splash. Using it or not ???
*/
/* If set_override() is used, message boxes will be popped behind splash. Using it or not ??? */
set_override();
// make sure window is centered
/* make sure window is centered */
int sw = DisplayWidth(fl_display, fl_screen);
int sh = DisplayHeight(fl_display, fl_screen);
position(sw/2 - w()/2, sh/2 - h()/2);
position(sw / 2 - w() / 2, sh / 2 - h() / 2);
show();
Fl::add_timeout(TIMEOUT_START, runner_cb, this);
// to keep splash at the top
/* to keep splash at the top */
#ifndef EDEWM_HAVE_NET_SPLASH
global_splash = this;
XSelectInput(fl_display, RootWindow(fl_display, fl_screen), SubstructureNotifyMask);
@ -249,8 +227,7 @@ void Splash::run(void) {
/* called when splash option is on */
bool Splash::next_client(void) {
if(slist->empty())
return false;
E_RETURN_VAL_IF_FAIL(slist->size() > 0, false);
if(counter == 0)
slist_it = slist->begin();
@ -260,11 +237,11 @@ bool Splash::next_client(void) {
return false;
}
E_ASSERT(counter < slist->size() && "Internal error; 'counter' out of bounds");
const char* msg = (*slist_it)->description.c_str();
const char* cmd = (*slist_it)->exec.c_str();
const char *msg, *cmd;
msg = (*slist_it)->description.c_str();
cmd = (*slist_it)->exec.c_str();
icons[counter]->show();
msgbox->label(msg);
@ -281,8 +258,7 @@ bool Splash::next_client(void) {
/* called when splash option is off */
bool Splash::next_client_nosplash(void) {
if(slist->empty())
return false;
E_RETURN_VAL_IF_FAIL(slist->size() > 0, false);
if(counter == 0)
slist_it = slist->begin();
@ -297,7 +273,7 @@ bool Splash::next_client_nosplash(void) {
const char* msg = (*slist_it)->description.c_str();
const char* cmd = (*slist_it)->exec.c_str();
printf("%s\n", msg);
E_DEBUG(E_STRLOC ": Starting '%s'...\n", msg);
/* run command */
if(!dryrun)

Some files were not shown because too many files have changed in this diff Show More