Compare commits

...

246 commits
5.56 ... master

Author SHA1 Message Date
Kang Yu
ae8da16834 #403, fix crash due to empty history record 2025-05-08 13:43:36 -07:00
Kang Yu
6745982d60 simplify help on DPS, remove Shift + click desktop window 2025-05-05 18:12:11 -07:00
Kang Yu
cd29b29282 simplify DPS code 2025-05-05 18:09:34 -07:00
Kang Yu
3a473bdc10 [dual pos switch] use first diff pos as background match 2025-05-05 17:49:23 -07:00
Kang Yu
3d2ed7395c tag 5.65 2025-05-03 23:26:00 -07:00
Kang Yu
3884c4446f no fast capture if window is marked no restore 2025-05-03 23:23:51 -07:00
Kang Yu
11d0c30ddb disable double restore full screen window due to invisible window issue 2025-05-03 23:12:28 -07:00
Kang Yu
f7eb0abe43 speedup inheritance in case window create event is delayed 2025-05-03 22:24:20 -07:00
Kang Yu
cad1ec393f restore process priority 10 seconds after startup 2025-05-03 17:24:44 -07:00
Kang Yu
4df563f1bb speedup PW startup restore by setting set process priority to high during the first 10 seconds of PW starting 2025-05-03 16:44:10 -07:00
Kang Yu
e8f06c1368 no need to write xml when restore finished, as it is done in session end 2025-05-03 16:15:24 -07:00
Kang Yu
2c06fe1684 #388, fix mismatch killed window for jEdit 2025-05-01 23:43:38 -07:00
Kang Yu
9e85ee5810 #369, fix crash on windows 11 when launching webpage 2025-05-01 17:55:09 -07:00
Kang Yu
4998a104ea tag 5.64 2025-05-01 15:46:41 -07:00
Kang Yu
1fd82f35c8 avoid trigger batch restore in restore single window mode 2025-05-01 15:42:07 -07:00
Kang Yu
e7b141e095 further speedup auto-restore-new-window 2025-05-01 15:01:17 -07:00
Kang Yu
304c654e80 inherit window in stack order (last kill, first inherit) 2025-05-01 14:55:44 -07:00
Kang Yu
9661f8bd79 undo wild match for non-resizable window 2025-05-01 11:30:27 -07:00
Kang Yu
5d26d86e28 speedup auto-restore-new-window, reduce killed window entry by wild matching non-resizable window which will not be restored 2025-05-01 11:16:42 -07:00
Kang Yu
f05d569387 #400, fix wrong mismatch of dialog of different style 2025-05-01 09:57:36 -07:00
Kang Yu
f66dc3afd8 match new window with killed one in LIFO style 2025-04-30 19:47:32 -07:00
Kang Yu
5f666b20d1 avoid wrong matching 2025-04-28 16:36:47 -07:00
Kang Yu
2d695d11bf tag 5.63, update help for command line option change 2025-04-28 14:53:26 -07:00
Kang Yu
8da7d9b4bc turn on -auto_restore_new_window_to_last_capture again 2025-04-28 14:24:18 -07:00
Kang Yu
f7a1f92343 fix wrong tick value for 5 min 2025-04-28 14:16:45 -07:00
Kang Yu
8771c2edd7 disable auto restore from db/xml at pw start if system is up more than 5 min 2025-04-28 14:14:31 -07:00
Kang Yu
f34fffa574 disable auto restore from db if system is up more than 5 min 2025-04-28 14:10:41 -07:00
Kang Yu
cce0f7f52d refix #369, #388, #392: improve algorithm matching new window to killed one. Add command option -pos_match_threshold, using 40 as default value 2025-04-28 13:50:30 -07:00
Kang Yu
8c5d6475ad fix broken -auto_restore_new_window_to_last_capture 2025-04-28 10:58:58 -07:00
Kang Yu
052cb05f53 refix delay activating webpage commander window when curosr is beam (user might be typing) 2025-04-27 22:51:01 -07:00
Kang Yu
40f8f5cefd delay activating webpage commander window when cursor is beam (user might be typing) 2025-04-27 22:11:42 -07:00
Kang Yu
7dc0cbee82 relax title match when inherit killed window 2025-04-27 21:18:07 -07:00
Kang Yu
1a5d9442d2 relax class name and position match when inherit killed window 2025-04-27 21:14:09 -07:00
Kang Yu
d36bf0c56c reduce cpu load on non-window object 2025-04-27 14:56:03 -07:00
Kang Yu
9224d62191 postpone capture to avoid wrong matching to killed window 2025-04-26 22:55:31 -07:00
Kang Yu
e41caba220 improve debug message 2025-04-26 22:29:16 -07:00
Kang Yu
769f35b681 debug print inherited window handle 2025-04-26 18:37:18 -07:00
Kang Yu
2ba0a5395b move inherit killed window out of IsWindowMoved() to CaptureWindow() 2025-04-26 15:25:31 -07:00
Kang Yu
e4be317e77 improve accuracy of matching killed window based on position similarity 2025-04-25 23:39:44 -07:00
Kang Yu
fb5f538b88 improve re-entrance protection using lock 2025-04-18 14:29:29 -07:00
Kang Yu
3b5813bb35 reduce event loggging of regular trimming of position history 2025-04-18 13:20:28 -07:00
Kang Yu
de1b815d57 fix dead-loop in TrimQueue() 2025-04-14 21:20:21 -07:00
Kang Yu
62452f3e0b fix dead-loop in TrimQueue(), causing auto-restore to hang, possibly due to wrong inheritance 2025-04-14 16:25:06 -07:00
Kang Yu
0adf762fa0 fix wrong capture due to improper unfreeze 2025-03-24 10:35:28 -07:00
Kang Yu
05a740a21f unlock unknown display session when any window is moved/resized/minimize/unminimized 2025-03-19 16:01:07 -07:00
Kang Yu
4330c95216 refactor TryInheritWindow(), making it safe to be called for both new and captured window 2025-03-17 20:53:17 -07:00
Kang Yu
23b63d09ea tag 5.62, update help 2025-03-17 16:40:29 -07:00
Kang Yu
6097ab4bc7 turn off auto restore existing window to last capture 2025-03-17 16:36:03 -07:00
Kang Yu
aacaefc205 #369, #388, #392: turn off auto-restore new window off by default 2025-03-17 16:30:49 -07:00
Kang Yu
557a3bbddb #369, #388, #392: newly created window auto-restored to wrong place due to matching to incorrect entry with different window title 2025-03-17 14:29:11 -07:00
Kang Yu
189611ad3a improve event message for inherit window 2025-03-17 14:22:16 -07:00
Kang Yu
86926ffd27 #388, fix missing capture of maximized window 2025-03-16 15:36:56 -07:00
Kang Yu
10dd03498a #389, persist exception when running PW with -ignored_process 2025-03-08 16:44:40 -08:00
Kang Yu
3c585c1dab tag 5.61 2025-03-08 15:54:57 -08:00
Kang Yu
172cbdc35c undo speedup inheritance of killed window on 1/29 2025-03-08 15:29:05 -08:00
Kang Yu
5fc59d5bc5 #368, #388: fix mismatching of new window due to improper timing 2025-03-08 14:16:05 -08:00
Kang Yu
8c710ab55c speculative fix for failure to restore, due to write xml dump in realtime event handler 2025-02-04 12:18:47 -08:00
Kang Yu
4f7479b0b7 fix compile warning 2025-02-04 11:50:13 -08:00
Kang Yu
c15ab870ac fix crash calling GetWindowTextLength() 2025-02-04 11:01:30 -08:00
Kang Yu
c719aee32f update help on -capture_floating_window 2025-02-02 21:59:58 -08:00
Kang Yu
2cfa8ce92f update help on auto restore new/existing window to last capture 2025-02-02 21:45:46 -08:00
Kang Yu
83c228b6fe tag 5.60 2025-02-02 20:55:56 -08:00
Kang Yu
5d6c71d03a update help on -restore_snapshot 2025-02-02 20:54:31 -08:00
Kang Yu
c58027bb9c update help on new command option -restore_snapshot 2025-02-02 20:46:08 -08:00
Kang Yu
62a03e4ed3 fix typo 2025-02-02 20:40:50 -08:00
Kang Yu
fe06972d58 rename -dump_window_pos_at_exit to -dum_window_position_history 2025-02-02 20:39:47 -08:00
Kang Yu
b70db0aa53 reliably restore full-screen rdp window 2025-02-02 16:00:53 -08:00
Kang Yu
2bfd021698 do not auto-restore upon program start 2025-02-02 13:33:54 -08:00
Kang Yu
0e622b8021 #354, add command option -restore_snapshot "[0-9a-z]" 2025-02-02 11:58:06 -08:00
Kang Yu
5a794baf8b reliably detect full screen mode 2025-01-31 10:24:42 -08:00
Kang Yu
a5dd48becf fix typo 2025-01-30 19:32:44 -08:00
Kang Yu
13cd0ab8d5 no auto inherit when restore from db 2025-01-30 19:29:10 -08:00
Kang Yu
52231e20ab fix missing opportunity to inherit window by adding create event processing 2025-01-30 19:04:03 -08:00
Kang Yu
362df4c720 send window without history to background when restore snapshot 2025-01-30 11:38:07 -08:00
Kang Yu
5925950f24 speedup inheritance of killed window 2025-01-29 23:51:20 -08:00
Kang Yu
c292fdd1b1 fix missing z-order recovery when inherit killed window 2025-01-29 23:01:14 -08:00
Kang Yu
ecd57678e1 #369, fix wrong matching of killed window pos of different display config 2025-01-29 22:05:41 -08:00
Kang Yu
145769a886 disable putting no record window to bottom z-order 2025-01-29 21:29:48 -08:00
Kang Yu
b32fbee4d0 revert no record window hack 2025-01-29 21:28:33 -08:00
Kang Yu
cfb1793dc6 revert setting invalid curDisplayKey value causing PW stop responding 2025-01-29 21:23:21 -08:00
Kang Yu
2b288cb295 no need to capture layout for window close event 2025-01-18 11:30:11 -08:00
Kang Yu
04e569fbcb #369, more consistent behavior for -delay_auto_restore 2025-01-07 22:21:58 -08:00
kangyu-california
3c6f053b00
Merge pull request #368 from ImKventis/master
Maintain custom set icon
2025-01-06 10:50:13 -08:00
ImKventis
bac953a9e4 Maintain custom set icon 2025-01-06 15:52:42 +00:00
Kang Yu
ab1f69d06b fix failure to translate mouse click on webpage commander window into page up/down event for web browser 2025-01-02 21:13:26 -08:00
Kang Yu
44b17d4225 improve robustness of full screen detection #94 2024-12-13 11:29:24 -08:00
Kang Yu
23fd9ba665 fix failure to inherit position history from killed window 2024-12-11 12:23:48 -08:00
Kang Yu
7d431a22f1 disable UndoCapture() for full screen gaming session 2024-12-10 18:27:42 -08:00
Kang Yu
384154254a reliably restore full screen rdp window 2024-12-10 13:09:56 -08:00
Kang Yu
041ddcbb6d fix early capture 2024-12-09 17:22:13 -08:00
Kang Yu
6764546824 missing reset causing failure to activate window 2024-12-08 13:15:51 -08:00
Kang Yu
453a4cb9e9 do not auto restore activated floating window 2024-12-07 13:29:26 -08:00
Kang Yu
6feaa24d92 fix KeyNotFound crash 2024-12-07 13:18:13 -08:00
Kang Yu
b03ddd4470 simplify Timer lambda 2024-12-07 13:17:11 -08:00
Kang Yu
886182afc1 refactor foregroundTimerCallback() 2024-12-07 11:47:32 -08:00
Kang Yu
b519812fa5 invalidate curDisplayKey during display changing to avoid miscapture 2024-12-06 15:15:50 -08:00
Kang Yu
cf4a966e28 keep window size when restore floating window (thickframe style is 0) 2024-11-25 17:54:08 -08:00
Kang Yu
9334f516a1 let -foreground_background_dual_position switch control the new feature introduced in last commit 2024-11-22 21:58:48 -08:00
Kang Yu
21e664b4c0 new feature: ctrl click desktop window to bring foreground window to previous background z-order 2024-11-22 18:30:50 -08:00
Kang Yu
bc25a0ea01 optimize coding without move timer 2024-11-22 15:19:37 -08:00
Kang Yu
d4742d6127 turn on fast restore by default 2024-11-22 14:50:20 -08:00
Kang Yu
ddbbe88032 fix wrong assumption causing mis-capture and failure for dual position switching 2024-11-21 23:48:56 -08:00
Kang Yu
021205f255 sequentially start foreground timer and capture timer 2024-11-21 16:00:39 -08:00
Kang Yu
a398bba08a fix freeze capture not working 2024-11-21 10:56:28 -08:00
Kang Yu
e3b184b68d refix crash when entering full-screen gaming mode 2024-11-20 23:19:26 -08:00
Kang Yu
fffdf03c10 fix crash 2024-11-19 22:17:49 -08:00
Kang Yu
0d6940b6ec avoid crash 2024-11-19 21:26:05 -08:00
Kang Yu
12e6522a78 #158, explicitly inherit position history from killed window 2024-11-19 20:40:12 -08:00
Kang Yu
9e63a2b853 #158, add switch to disable auto restore window to last capture 2024-11-18 11:08:28 -08:00
Kang Yu
b392ac84f9 rename a variable 2024-11-18 10:55:19 -08:00
Kang Yu
573b453704 simplify print format 2024-11-13 15:36:31 -08:00
Kang Yu
cabca12856 print POINT 2024-11-13 14:30:11 -08:00
Kang Yu
7f5f465362 reliably send window to bottom z-order if no qualified restore record is found 2024-11-12 22:47:19 -08:00
Kang Yu
cd328c2979 avoid bogus capture 2024-11-09 22:20:25 -08:00
Kang Yu
7dfd7f5616 disable -fast_restore by default due to concern of out of order event processing 2024-11-06 10:25:21 -08:00
Kang Yu
3cb7f93cee refine message print 2024-11-04 17:38:58 -08:00
Kang Yu
e4571e4f34 accelarate auto restore for pop up window activated from previous display config 2024-11-04 11:19:53 -08:00
Kang Yu
4d6b24d8fc #158, auto restore to last position for newly launched window 2024-11-03 20:49:07 -08:00
Kang Yu
6910013026 avoid exception 2024-11-03 13:53:33 -08:00
Kang Yu
0d5d0372ee minor restore speed up 2024-11-03 11:26:29 -08:00
Kang Yu
b758b474cd rename variable 2024-11-03 10:45:23 -08:00
Kang Yu
3847a6eff0 persist disable upgrade notice 2024-11-02 22:47:29 -07:00
Kang Yu
94c7bd18c4 show release notes when upgrade 2024-11-02 17:41:00 -07:00
Kang Yu
34c0dbd0cf do visibility match when inherit position history 2024-11-02 11:58:17 -07:00
Kang Yu
1a13cf8b11 reduce event logs for zorder restore 2024-11-01 14:55:45 -07:00
Kang Yu
cea1088a7d capture floating window by default, disable by -capture_floating_window=0 2024-10-31 22:48:13 -07:00
Kang Yu
8e33aab670 fast restore by default, disable by -fast_restore=0 2024-10-31 22:46:24 -07:00
Kang Yu
c7f0f29961 increase the delta threshold of taskbar width/height change for restore 2024-10-31 22:29:51 -07:00
Kang Yu
5296f7dff5 command option -fix_taskbar_no_game 2024-10-31 22:16:40 -07:00
Kang Yu
dfec7db6b7 avoid moving mis-aligned taskbar 2024-10-31 21:41:40 -07:00
Kang Yu
80c43c2051 reliably disable bogus taskbar move after exit fullscreen gaming 2024-10-31 11:05:44 -07:00
Kang Yu
db3201ade2 simplify capture latency accuracy 2024-10-29 16:52:43 -07:00
Kang Yu
efc2d0bb67 turn off fast restore by default 2024-10-26 19:03:43 -07:00
Kang Yu
0d3d5c24f3 fix failure to restore taskbar after full-screen gaming play 2024-10-26 15:57:08 -07:00
Kang Yu
76118726a8 avoid erroneous moving taskbar 2024-10-25 19:57:26 -07:00
Kang Yu
ee8603c5b6 speed up auto-restore by setting high PW process priority early 2024-10-25 15:51:45 -07:00
Kang Yu
9cb7fd2e90 #355, clean exit without error 2024-10-23 23:52:03 -07:00
Kang Yu
382a427a47 allow initial capture before initial auto restore 2024-10-23 23:35:46 -07:00
Kang Yu
c0e1af0c10 #158, initial auto restore using the last capture from history 2024-10-23 21:48:15 -07:00
Kang Yu
a40273567a reliably restore full screen rdp window 2024-10-22 09:40:15 -07:00
Kang Yu
c5c12dcad3 unified RemoveInvalidCapture() usage 2024-10-20 23:12:08 -07:00
Kang Yu
6cbfea8f69 fix failure to restore full screen rdp window 2024-10-20 22:45:04 -07:00
Kang Yu
cee860c2d4 dump debug window history in separate xml file 2024-10-18 20:42:48 -07:00
Kang Yu
a515bd6e6e reliably restore full screen window by simulating double clicking 2024-10-18 18:47:46 -07:00
Kang Yu
23fd772152 synchronize undoCapture() and WriteDataDump() 2024-10-18 16:27:47 -07:00
Kang Yu
b02d160872 remove invalid capture from history dump 2024-10-17 13:15:11 -07:00
Kang Yu
b758dfed2d attempt to fix exception using lock 2024-10-16 20:47:20 -07:00
Kang Yu
96caaa9cd8 #360, highlight importance to run PW as admin 2024-10-16 00:17:08 -07:00
Kang Yu
5d15d4c042 undo early raising process priority due to restore failure 2024-10-15 12:12:11 -07:00
Kang Yu
580a0864e2 auto dump xml when changing from normal display session 2024-10-12 19:26:45 -07:00
Kang Yu
748d86ddc8 fix read/write conflict due to shallow copy 2024-10-12 17:06:30 -07:00
Kang Yu
a98717ab4e dump history xml when display changing 2024-10-12 15:04:15 -07:00
Kang Yu
3d38b70cf1 remove unused .resx files 2024-10-11 23:28:54 -07:00
Kang Yu
d39563b9b5 #356, restrict window match for unique title 2024-10-10 15:11:40 -07:00
Kang Yu
df594f6045 #356, matching window title has higher priority than matching window position when inherit from killed window 2024-10-10 12:28:03 -07:00
Kang Yu
c8575c1b03 reduce size of history xml 2024-10-08 22:46:38 -07:00
Kang Yu
cc2fa3311c avoid auto capture in fullscreen gaming 2024-10-08 16:52:10 -07:00
Kang Yu
ea1b7baea6 avoid capture fullscreen gaming session 2024-10-08 15:59:30 -07:00
Kang Yu
346e5fdb36 deactivate session when fullscreen gaming 2024-10-08 15:26:15 -07:00
Kang Yu
bff39c71dc deep copy to avoid unintended data contamination 2024-10-07 11:25:56 -07:00
Kang Yu
f23646e480 attempt to fix unknown exception 2024-10-03 11:45:48 -07:00
Kang Yu
31e0ebc85e #357, invalid IntPtr blocks taskbar restore 2024-10-03 11:14:36 -07:00
Kang Yu
860034633a #357, allow taskbar restore during full-screen game play when -fix_taskbar=1 2024-10-02 17:01:56 -07:00
kangyu-california
9d80f6c1b2
Update Help.md 2024-10-01 18:19:36 -07:00
Kang Yu
61133e14b5 enable crash in debug mode 2024-09-30 14:18:26 -07:00
Kang Yu
6b2bbba706 #356, record change of window title 2024-09-30 12:26:19 -07:00
Kang Yu
2fd2ff129b avoid bogus taskbar restore when exit full-screen game 2024-09-24 10:04:11 -07:00
Kang Yu
cf5e26af87 resolve handle conflict for core window 2024-09-22 16:16:06 -07:00
Kang Yu
a541eb0a6c catch exception in resolving window handle collision 2024-09-21 23:46:37 -07:00
Kang Yu
c47246cc65 print process name to debug window handle conflict 2024-09-21 23:33:34 -07:00
Kang Yu
4fc6f7ad40 refix live/dead window handle conflict, assuming hwnd handle only uses 3 bytes 2024-09-21 23:27:44 -07:00
Kang Yu
bcd23a31f2 resolve window handle conflict btw live and dead record 2024-09-21 13:05:03 -07:00
Kang Yu
2b0c470ce5 ctrl exit to test restart 2024-09-20 19:44:29 -07:00
Kang Yu
665aed45f7 hide icon before exit 2024-09-18 17:06:25 -07:00
Kang Yu
ed3ee46735 speedup program exit 2024-09-18 17:03:42 -07:00
Kang Yu
e04dc2ee07 speedup auto restore 2024-09-18 14:37:46 -07:00
Kang Yu
5d286a467d tag 5.59, update readme/help 2024-09-16 17:02:41 -07:00
Kang Yu
ebe7c5d33d webpage commander: reduce window focus shifting when hand cursor is displayed (possible menu selection) 2024-09-15 15:26:01 -07:00
Kang Yu
08ef381f96 repeated browser activate events causes webpage menu disappear 2024-09-15 12:57:00 -07:00
Kang Yu
090fa0e3ad dump all window history including dead ones 2024-09-15 10:38:04 -07:00
Kang Yu
2763659b4c dump dead window history together with live windows 2024-09-14 21:52:07 -07:00
Kang Yu
f6007a4b62 minor code simplify 2024-09-12 18:05:24 -07:00
Kang Yu
d22a183554 remove history of oldest window first 2024-09-11 22:18:01 -07:00
Kang Yu
b575920805 refactor pw restart script 2024-09-11 21:19:55 -07:00
Kang Yu
2b73c3c2bc #352, add command option -capture_floating_window 2024-09-09 17:00:48 -07:00
Kang Yu
eea9165382 This reverts commit a45b967e5f. 2024-09-09 15:08:01 -07:00
Kang Yu
8d3816553b #348, do upgrade after pw process is killed 2024-08-28 17:09:45 -07:00
Kang Yu
e6f11c354d #348, insufficient delay causes failure to upgrade 2024-08-28 15:52:01 -07:00
Kang Yu
1b4f62ee7d fix typo causing wrong (legacy) icon used when new release is available. Update pwIconUpdate to be more harmonic 2024-08-28 15:35:17 -07:00
Kang Yu
800b6afa15 refine inherit log message 2024-08-28 14:20:18 -07:00
Kang Yu
452ef9017c tag 5.58 2024-08-27 19:56:19 -07:00
Kang Yu
1ef5e99d40 catch exception when dump position history xml 2024-08-27 19:32:13 -07:00
Kang Yu
7fd80af8bf dump window position for every auto restore 2024-08-27 18:55:22 -07:00
Kang Yu
e8322d5a8a persist snapshot captures on disk 2024-08-27 17:31:03 -07:00
Kang Yu
ef02d287d5 unify data structures so that dumped window_pos.xml can be used as deadApps 2024-08-27 17:06:43 -07:00
Kang Yu
a1a3574f73 persist snapshot taken time on hdd in real time 2024-08-27 15:02:53 -07:00
Kang Yu
1e580843ff fix exception when capture new windows 2024-08-18 15:23:09 -07:00
Kang Yu
4cece1ab9c launch webpage commander notification page from current browser window 2024-08-17 13:52:18 -07:00
Kang Yu
0a6c00c3a7 refactor disable_webpage_commander 2024-08-17 12:49:39 -07:00
Kang Yu
697e79b1ba #347, remember the choice of disable webpage commander upon PW restart 2024-08-16 22:45:44 -07:00
Kang Yu
7bd8511bb9 #347, longer balloontip tip for webpage commander notification 2024-08-14 17:56:04 -07:00
Kang Yu
2a7a108748 #347, avoid invoke webpage commander window when pressing hotkey on taskbar 2024-08-14 17:49:48 -07:00
Kang Yu
3240042a68 avoid notification of webpage commander hotkey if not invoked in web browser 2024-08-14 17:34:52 -07:00
Kang Yu
ae75d66172 #347, show notifications when webpage commander is invoked for the first time 2024-08-14 16:39:42 -07:00
Kang Yu
05dec2e6dd add webpage_commander.md 2024-08-14 15:47:32 -07:00
Kang Yu
8b12f6e4a8 rewind auto capture which happened right before session lock 2024-08-12 10:43:23 -07:00
Kang Yu
eade031052 refactor UndoCapture(DateTime) 2024-08-12 10:38:34 -07:00
Kang Yu
b13bcf0b58 fix too many attempts to restore taskbar size for rdp session 2024-08-11 21:02:31 -07:00
Kang Yu
2d14ef2cb9 fix exception caused by data race 2024-08-11 16:32:22 -07:00
Kang Yu
bed63a11f4 avoid webpage activation disturb auto restore 2024-08-09 21:02:40 -07:00
Kang Yu
e7b52a035c do not capture webpage commander, also ignore its presence in z-order 2024-08-09 16:00:51 -07:00
Kang Yu
4136e5d2a1 refix #318, #346, create AppData/Local/PersistentWindows directory during startup 2024-08-08 12:00:57 -07:00
Kang Yu
e99518f23b catch occasional container iteration exception when starting full-screen game 2024-08-07 22:31:55 -07:00
Kang Yu
b1888cbf9b webpage commander: unhide commander window quickly when browser window is activated 2024-07-29 22:35:29 -07:00
Kang Yu
e5194d8660 webpage commander: try to show commander window when browser window is activated, disregard background pixel color 2024-07-29 19:03:15 -07:00
Kang Yu
ef6e0a6b37 sync pwIcon.ico with pwIcon.png 2024-07-29 10:57:53 -07:00
Kang Yu
451ecb9424 keep webpage commander visible (with safe distance from mouse cursor) on top of non-uniform background (like video/picture) 2024-07-27 21:50:27 -07:00
Kang Yu
d3b1862113 webpage commander: keep commander window visible while not affecting menu operation in the webpage 2024-07-27 21:04:46 -07:00
Kang Yu
f81735509a webpage commander: avoid conflict with menu selection in webpage by delay re-display the commander window 2024-07-27 18:02:48 -07:00
Kang Yu
b8a03dd189 hide webpage commander window during mouse move, reduce flicker when unhide 2024-07-27 16:14:30 -07:00
Kang Yu
2b36e580b9 do not restore from db if previous restore point exist when launch pw 2024-07-26 23:01:56 -07:00
Kang Yu
806fcd6bd2 cleanup non-exist ico resource 2024-07-26 22:07:41 -07:00
Kang Yu
185b34268c catch exception in WinEventProc() 2024-07-26 21:58:48 -07:00
Kang Yu
db6ca09f65 rename variables 2024-07-26 21:53:51 -07:00
Kang Yu
ff53cc352d support customized pw update icon with file named as pwIconUpdate(.ico, .png) 2024-07-26 20:49:57 -07:00
Kang Yu
5ecc8bdf1b #342, add update icon for legacy mode. Replace .ico with .png. Beautify pw icon 2024-07-26 20:43:41 -07:00
Kang Yu
a723695ff4 consolidate lastCaptureTime into snapshotTakenTime for complete history dump 2024-07-19 22:30:08 -07:00
Kang Yu
c6877b688f #341, restore Computer folder for Win7 2024-07-15 20:53:37 -07:00
Kang Yu
d1cf04ec3d #341, restore This PC folder in explorer 2024-07-15 17:58:15 -07:00
Kang Yu
8890db68e6 tag 5.57 2024-07-13 22:39:51 -07:00
Kang Yu
cf7a4b831a fix typo 2024-07-13 22:34:15 -07:00
Kang Yu
28a02c0a12 update help 2024-07-13 22:31:32 -07:00
Kang Yu
b782e9b034 #333, add command -delay_restart <seconds> to restart PW in hidden mode 2024-07-13 21:04:54 -07:00
Kang Yu
63334fa67c add command -dump_window_pos_at_exit=0 2024-07-13 15:30:27 -07:00
Kang Yu
5fc803757a dump window pos to xml file before exit, reload window pos from xml when PW start 2024-07-13 15:22:10 -07:00
Kang Yu
958624db0a minor code refactoring 2024-07-11 11:55:45 -07:00
Kang Yu
db2d8c5fb0 minor code refactoring 2024-07-11 11:55:21 -07:00
Kang Yu
dfe5dbd16c inherit killed window: improved matching for windows core app 2024-07-10 12:27:29 -07:00
Kang Yu
8d68937a96 fix typo 2024-07-09 09:51:51 -07:00
Kang Yu
88e5a24441 inherit killed window pos: apply first-in-first-match policy 2024-07-09 09:46:58 -07:00
Kang Yu
a5221064eb inherit killed window: update zorder information in deadApps as well 2024-07-08 17:39:24 -07:00
Kang Yu
74da136678 increase storage capacity of kill window to 1024 2024-07-08 16:49:19 -07:00
Kang Yu
9c7c17a5b7 simplify coding, more window title cleanup 2024-07-08 16:40:33 -07:00
Kang Yu
e166a3f89d inherit killed window pos: add default option when no exact match found 2024-07-07 22:49:07 -07:00
Kang Yu
2a95cebe6a coding style: change Int64 to long 2024-07-07 22:39:07 -07:00
Kang Yu
d0ed7aa288 #336, let menu observe -check_upgrade=0 2024-07-01 08:33:08 -07:00
32 changed files with 1611 additions and 1291 deletions

18
Help.md
View file

@ -6,8 +6,9 @@
| --- | --- |
| -gui=0 | Do not display the PersistentWindows icon on the System Tray. Effectively runs PersistentWindows as a service
| -splash=0 | No splash window at PersistentWindows startup
| -legacy_icon | Switch to the original icon (as of 5.49 release)
| -legacy_icon | Switch to the original icon ![pwIcon2small](https://github.com/user-attachments/assets/4827f67a-2ce1-4a83-86da-b4bfa6835026)
| -silent | No splash window, no balloon tip hint, no event logging
| -capture_floating_window=0 | Disable capture floating child window and dialog window position
| -ignore_process "notepad.exe;foo" | Avoid restoring windows for the processes notepad.exe and foo
| -debug_process "notepad.exe;foo" | Print the window positioning event logs in Event Viewer for the processes *notepad.exe* and *foo*
| -foreground_background_dual_position=0 | Turn off dual position switching
@ -15,6 +16,7 @@
| -hotkey "Q" | register Alt + Q as the hotkey to (de)activate webpage commander window, default hotkey is "W" (Alt + W)
| -ctrl_minimize_to_tray=0 | Turn off ctrl minimize window to notification tray
| -prompt_session_restore | Ask the user before restoring the window layout upon resuming the last session. This may help reduce the total restore time for remote desktop sessions on slow internet connections.
| -delay_restart 5 | Restart PersistentWindows in 5 seconds. This option should only be used in case normal start of PersistentWindows fails.
| -delay_auto_capture 1.0 | Adjust the lag between window move event and auto-capture to 1.0 second, the default lag is 3~4 seconds.
| *-delay_auto_restore 2.5* | Adjust the lag between monitor on/off event and auto-restore to 2.5 seconds (the default lag is 1 second). This is in case the restore is incomplete or the monitor fails to go to sleep due to the restore starting too early.
| -redraw_desktop | Redraw the whole desktop after a restore, in case some window workarea is not refreshed
@ -22,13 +24,17 @@
| -fix_offscreen_window=0 | Turn off auto correction of off-screen windows
| -fix_unminimized_window=0 | Turn off auto restore of unminimized windows. Use this switch to avoid undesirable window shifting during window activation, which comes with Event id 9999 : "restore minimized window ...." in event viewer.
|-auto_restore_new_display_session_from_db=0| Disable window restore from DB upon PC startup or switching display for the first time
|-auto_restore_existing_window_to_last_capture=1 | Turn on auto restore existing window from last capture upon PW start
|-auto_restore_new_window_to_last_capture=0 | Turn off auto restore new window to last killed position
|-pos_match_threshold 80 | Auto correct new window position to last killed position within range of 80 pixels, default is 40
| auto_restore_missing_windows=1 | When restoring from disk, restore missing windows without prompting the user
| auto_restore_missing_windows=2 | At startup, automatically restore missing windows from disk. The user will be prompted before restoring each missing window
| auto_restore_missing_windows=3 | At startup, automatically restore missing windows from disk without prompting the user
| -invoke_multi_window_process_only_once=0 | Launch an application multiple times when multiple windows of the same process need to be restored from the database.
| -check_upgrade=0 | Disable the PersistentWindows upgrade check
| -auto_upgrade=1 | Upgrade PersistentWindows automatically without user interaction
| -dump_window_position_history=0 | Disable window position history dump
| -restore_snapshot "0" | restore snapshot 0 and exit. The range of snapshot id is [0-9a-z], as well as "~" or "`", the last two special ids represent the last auto restore. Note the window z-order can not be fully retored using this method, due to lack of capability to do multi-pass restore.
---
### Shortcuts to capture/restore snapshots
@ -54,7 +60,6 @@
* Dual Position Switching functionality:
* Click the desktop window to bring the foreground window to its previous background position and Z-order.
* Shift + Click the desktop window to bring the foreground window to its *second* last background position. This is useful if the previous background position is mis-captured due to invoking start menu or other popups.
* Ctrl + Click the desktop window to bring the foreground window to its previous Z-order while keeping the current location and size.
* To cancel Dual Position Switching:
@ -110,7 +115,8 @@
| Alt + click commander window || send the mouse click to the underlying browser window
### Other features
* To replace the default app icon with your customized one:
* Rename your .ico (or .png) file as `pwIcon.ico` (or `pwIcon.png`) and copy it to the PersistentWindows program folder, or alternatively to `C:/Users/<YOUR_ID>/AppData/Local/PersistentWindows/`.
* Copy another icon file to the same directory and rename it to `pwIconBusy.*`. This icon is displayed when PersistentWindows is busy restoring windows.
* To replace the default app icons with customized one:
* Rename customized .ico (or .png) file as `pwIcon.ico` (or `pwIcon.png`) and copy it to the PersistentWindows program folder, or alternatively to `C:/Users/<YOUR_ID>/AppData/Local/PersistentWindows/`.
* Copy another ico/png file to the same directory and rename it to `pwIconBusy.*`. This icon is displayed when PersistentWindows is busy restoring windows.
* Copy yet another ico/png file to the same directory and rename it to `pwIconUpdate.*`. This icon is displayed when a new PersistentWindows release is available.

View file

@ -36,6 +36,7 @@
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
@ -93,21 +94,9 @@
</PackageReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="DbKeySelect.resx">
<DependentUpon>DbKeySelect.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="HotKeyWindow.resx">
<DependentUpon>HotKeyWindow.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="LayoutProfile.resx">
<DependentUpon>LayoutProfile.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="LaunchProcess.resx">
<DependentUpon>LaunchProcess.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="NameDbKey.resx">
<DependentUpon>NameDbKey.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -6,7 +6,6 @@ using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;
@ -21,25 +20,30 @@ namespace PersistentWindows.Common
private uint hotkey;
public static IntPtr commanderWnd = IntPtr.Zero;
public static bool invokedFromBrowser = false;
private static System.Timers.Timer aliveTimer;
private static int callerAliveTimer = -1; //for tracing the starting source of alive timer
private System.Timers.Timer mouseScrollDelayTimer;
private bool init = true;
private bool active = false;
private static bool tiny = false;
private static bool browserWindowActivated = false;
private static bool restoring = false;
private int origWidth;
private int origHeight;
private int mouseOffset = 0;
private int mouseOffset = 0; //mouse dithering to workaround mouse location mis-update issue in rdp session
private static POINT lastCursorPos;
private POINT lastWheelCursorPos;
private bool handCursor = false;
private bool ibeamCursor = false;
private int titleHeight;
private static int callerAliveTimer = -1; //for tracing the starting source of alive timer
private Color dfltBackColor;
private bool promptZkey = true;
private bool clickThrough = false;
private bool defocused = false;
private int totalWaitSecondsForWhiteColor = 0;
public HotKeyWindow(uint hkey)
{
@ -203,6 +207,7 @@ namespace PersistentWindows.Common
Visible = false;
IntPtr fgwnd = GetForegroundWindow();
User32.SetForegroundWindow(fgwnd);
FgSleep();
if (alt_key_pressed || clickThrough)
{
@ -273,7 +278,7 @@ namespace PersistentWindows.Common
StartAliveTimer(1);
}
bool IsBrowserWindow(IntPtr hwnd)
private bool IsBrowserWindow(IntPtr hwnd)
{
return PersistentWindowProcessor.IsBrowserWindow(hwnd);
}
@ -591,9 +596,16 @@ namespace PersistentWindows.Common
{
if (!from_menu)
{
IntPtr fgwnd = GetForegroundWindow();
if (!IsBrowserWindow(fgwnd))
IntPtr fgwnd = GetForegroundWindow(strict : true);
if (fgwnd == commanderWnd)
fgwnd = GetForegroundWindow();
if (IsBrowserWindow(fgwnd))
{
invokedFromBrowser = true;
}
else
{
invokedFromBrowser = false;
//forward hotkey
char c = Convert.ToChar(hotkey);
string cmd = $"%{c}";
@ -629,13 +641,18 @@ namespace PersistentWindows.Common
active = false;
}
}
}
public static void BrowserActivate(IntPtr hwnd, bool is_browser_window = true)
public static void BrowserActivate(IntPtr hwnd, bool is_browser_window = true, bool in_restore = false)
{
if (browserWindowActivated == is_browser_window)
return;
browserWindowActivated = is_browser_window;
restoring = in_restore;
Console.WriteLine($"browser activated {hwnd.ToString("X")}");
if (!tiny && !User32.IsWindowVisible(commanderWnd))
return;
@ -715,7 +732,7 @@ namespace PersistentWindows.Common
return result;
}
private bool IsSimilarColor(IntPtr hwnd, int x, int y, int xsize, int ysize)
private bool IsSimilarColor(IntPtr hwnd, int x, int y, int xsize, int ysize, Color px)
{
using (Bitmap screenPixel = new Bitmap(xsize, ysize))
{
@ -731,20 +748,16 @@ namespace PersistentWindows.Common
}
}
var p1 = screenPixel.GetPixel(0, 0);
var p2 = screenPixel.GetPixel(xsize - 1, 0);
Console.WriteLine($"pixel ({x}, {y}) {p1}");
for (int i = 1; i < xsize; ++i)
Console.WriteLine($"pixel ({x}, {y}) {px}");
for (int i = 0; i < xsize; ++i)
{
Color p = screenPixel.GetPixel(i, i);
if (DiffColor(p, p1) > 10)
if (DiffColor(p, px) > 15)
return false;
p1 = p;
p = screenPixel.GetPixel(xsize - i - 1, i);
if (DiffColor(p, p2) > 10)
if (DiffColor(p, px) > 15)
return false;
p2 = p;
}
return true;
@ -783,6 +796,37 @@ namespace PersistentWindows.Common
}
}
private bool IsSameColor(IntPtr hwnd, int x, int y, int xsize, int ysize, Color px)
{
using (Bitmap screenPixel = new Bitmap(xsize, ysize))
{
using (Graphics gdest = Graphics.FromImage(screenPixel))
{
using (Graphics gsrc = Graphics.FromHwnd(hwnd))
{
IntPtr hsrcdc = gsrc.GetHdc();
IntPtr hdc = gdest.GetHdc();
Gdi32.BitBlt(hdc, 0, 0, xsize, ysize, hsrcdc, x, y, (int)CopyPixelOperation.SourceCopy);
gdest.ReleaseHdc();
gsrc.ReleaseHdc();
}
}
Console.WriteLine($"pixel ({x}, {y}) {px}");
for (int i = 0; i < xsize; ++i)
{
var p = screenPixel.GetPixel(i, i);
if (p.ToArgb() != px.ToArgb())
return false;
p = screenPixel.GetPixel(xsize - i - 1, i);
if (p.ToArgb() != px.ToArgb())
return false;
}
return true;
}
}
private void AliveTimerCallBack(Object source, ElapsedEventArgs e)
{
if (!active)
@ -793,12 +837,15 @@ namespace PersistentWindows.Common
IntPtr fgwnd = GetForegroundWindow();
if (!PersistentWindowProcessor.IsBrowserWindow(fgwnd))
{
if (browserWindowActivated)
{
if (browserWindowActivated || restoring)
StartAliveTimer(6, 1000);
return;
}
Visible = false;
else
Visible = false;
return;
}
else if (restoring)
{
StartAliveTimer(6, 1000);
return;
}
@ -823,7 +870,9 @@ namespace PersistentWindows.Common
}
else if (Math.Abs(cursorPos.X - lastCursorPos.X) > 3 || Math.Abs(cursorPos.Y - lastCursorPos.Y) > 3)
{
ibeamCursor = false;
//mouse moving, continue monitor
totalWaitSecondsForWhiteColor = 0;
}
else
{
@ -831,39 +880,53 @@ namespace PersistentWindows.Common
if (hCursor == Cursors.Default.Handle)
{
handCursor = false;
if (!commanderWndUnderCursor && !IsSimilarColor(IntPtr.Zero, cursorPos.X - Width/2, cursorPos.Y - Height/2, 12, 12))
if (callerAliveTimer == 6)
{
// hide hotkey window to allow click through possible link
Visible = false;
clickThrough = true;
//browser activation
;
}
else if (!commanderWndUnderCursor && !IsUniColor(IntPtr.Zero, cursorPos.X - Width / 2, cursorPos.Y - Height / 2, 12, 12))
{
// shift commander window to allow click possible link
Left = cursorPos.X - 10;
Top = cursorPos.Y - 10;
totalWaitSecondsForWhiteColor = 0;
StartAliveTimer(11, 1000);
return;
}
if (!commanderWndUnderCursor && !IsUniColor(IntPtr.Zero, cursorPos.X - Width / 2, cursorPos.Y - Height / 2, 12, 12))
else if (!commanderWndUnderCursor && !IsSimilarColor(IntPtr.Zero, cursorPos.X - Width / 2, cursorPos.Y - Height / 2, 1, 1, Color.White))
{
Left = cursorPos.X - 10;
Top = cursorPos.Y - 10;
StartAliveTimer(11, 1000);
return;
// wait for possible menu selection within webpage
++totalWaitSecondsForWhiteColor;
if (Visible && totalWaitSecondsForWhiteColor < 3)
{
StartAliveTimer(11, 1000);
return;
}
}
}
else if (hCursor == Cursors.IBeam.Handle)
{
ibeamCursor = true;
Visible = false;
StartAliveTimer(11, 1000);
return;
}
else if (hCursor == Cursors.Cross.Handle || handCursor)
{
ibeamCursor = false;
StartAliveTimer(7);
return;
}
totalWaitSecondsForWhiteColor = 0;
bool regain_focus = true;
bool change_to_visible = false;
if (!Visible)
{
Visible = true;
change_to_visible = true;
TopMost = true;
if (defocused)
{
@ -871,7 +934,7 @@ namespace PersistentWindows.Common
regain_focus = false;
}
}
else if (!handCursor)
else if (hCursor == Cursors.Default.Handle)
{
/*
if (!commanderWndUnderCursor)
@ -882,15 +945,29 @@ namespace PersistentWindows.Common
*/
regain_focus = !commanderWndUnderCursor;
}
else if (!handCursor)
{
regain_focus = false;
}
if (ibeamCursor && hCursor == Cursors.Default.Handle)
//&& Math.Abs(cursorPos.X - lastCursorPos.X) < 3 && Math.Abs(cursorPos.Y - lastCursorPos.Y) < 3)
{
ibeamCursor = false;
StartAliveTimer(11, 1000);
return;
}
// let tiny hotkey window follow cursor position
ResetHotKeyVirtualDesktop();
ResetHotkeyWindowPos();
if (change_to_visible)
Visible = true;
if (regain_focus)
{
User32.SetForegroundWindow(Handle);
User32.SetFocus(Handle);
}
ResetHotkeyWindowPos();
if (hCursor == Cursors.Default.Handle)
{
@ -903,6 +980,7 @@ namespace PersistentWindows.Common
// hand cursor shape
if (!handCursor)
{
ibeamCursor = false;
handCursor = true;
Left -= 10;
}
@ -1054,9 +1132,9 @@ namespace PersistentWindows.Common
User32.SetForegroundWindow(Handle);
}
private static IntPtr GetForegroundWindow()
public static IntPtr GetForegroundWindow(bool strict = false)
{
return PersistentWindowProcessor.GetForegroundWindow();
return PersistentWindowProcessor.GetForegroundWindow(strict);
}
private void FormSizeChanged(object sender, EventArgs e)

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -1,7 +1,10 @@
using System;
using System.Text;
using System.Xml;
using System.Runtime.Serialization;
using PersistentWindows.Common.WinApiBridge;
using PersistentWindows.Common.Diagnostics;
namespace PersistentWindows.Common.Models
{
@ -23,6 +26,8 @@ namespace PersistentWindows.Common.Models
public bool IsFullScreen { get; set; }
public bool IsMinimized { get; set; }
public bool IsInvisible { get; set; }
public long Style { get; set; }
public long ExtStyle { get; set; }
// for restore window position to display session end time
public DateTime CaptureTime { get; set; }
@ -55,7 +60,15 @@ namespace PersistentWindows.Common.Models
public override string ToString()
{
//return string.Format("{0}.{1} {2}", ProcessId, HWnd.ToString("X8"), ProcessName);
return string.Format("{0}.{1:x8} {2}", ProcessId, HWnd.ToInt64(), ProcessName);
//return string.Format("process:{0:x4} hwnd:{1:x6} {2}", ProcessId, HWnd.ToInt64(), ProcessName);
DataContractSerializer dcs = new DataContractSerializer(typeof(ApplicationDisplayMetrics));
StringBuilder sb = new StringBuilder();
using (XmlWriter xw = XmlWriter.Create(sb))
{
dcs.WriteObject(xw, this);
}
string xml = sb.ToString();
return xml;
}
}
}

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -41,6 +41,7 @@ namespace PersistentWindows.Common.WinApiBridge
EVENT_SYSTEM_IME_KEY_NOTIFICATION = 0x0029,
EVENT_SYSTEM_END = 0x00FF,
EVENT_OBJECT_CREATE = 0x8000,
EVENT_OBJECT_DESTROY = 0x8001,
EVENT_OBJECT_REORDER = 0x8004,
EVENT_OBJECT_LOCATIONCHANGE = 0x800B,
@ -623,6 +624,9 @@ namespace PersistentWindows.Common.WinApiBridge
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hHandle);
[DllImport("kernel32")]
public static extern UInt64 GetTickCount64();
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess,

View file

@ -28,6 +28,10 @@ namespace PersistentWindows.Common.WinApiBridge
X = x;
Y = y;
}
public override string ToString()
{
return string.Format($"({X}, {Y})");
}
}
[StructLayout(LayoutKind.Sequential)]
@ -57,5 +61,11 @@ namespace PersistentWindows.Common.WinApiBridge
{
return string.Format("({0}, {1}), {2} x {3}", Left, Top, Width, Height);
}
public int Diff(RECT r)
{
int diff = Math.Abs(Left - r.Left) + Math.Abs(Right - r.Right) + Math.Abs(Top - r.Top) + Math.Abs(Bottom - r.Bottom);
return diff / 4;
}
}
}

View file

@ -1,6 +1,8 @@
using System;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO;
using PersistentWindows.Common;
using PersistentWindows.Common.WinApiBridge;
@ -10,6 +12,7 @@ namespace PersistentWindows.SystrayShell
{
public class HotKeyForm : Form
{
static bool init = true;
static HotKeyWindow hkwin = null;
static Thread messageLoop;
@ -60,9 +63,42 @@ namespace PersistentWindows.SystrayShell
User32.KeyModifier modifier = (User32.KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed.
int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed.
Program.HideRestoreTip(false); //hide icon
Program.HideRestoreTip(); //show icon
IntPtr fgWnd = PersistentWindowProcessor.GetForegroundWindow(strict : true);
hkwin.HotKeyPressed(from_menu : false);
if (PersistentWindowProcessor.IsBrowserWindow(fgWnd))
{
Program.HideRestoreTip(false); //hide icon
Program.HideRestoreTip(); //show icon
if (init)
{
init = false;
string webpage_commander_notification = Path.Combine(Program.AppdataFolder, "webpage_commander_notification");
if (File.Exists(webpage_commander_notification))
{
Program.systrayForm.notifyIconMain.ShowBalloonTip(8000, "webpage commander is invoked via hotkey", "Press the hotkey (Alt + W) again to revoke", ToolTipIcon.Info);
}
else
{
try
{
File.Create(webpage_commander_notification);
uint processId;
User32.GetWindowThreadProcessId(fgWnd, out processId);
string procPath = PersistentWindowProcessor.GetProcExePath(processId);
Process.Start(procPath, Program.ProjectUrl + "/blob/master/webpage_commander.md");
}
catch (Exception ex)
{
Log.Error(ex.ToString());
Program.systrayForm.notifyIconMain.ShowBalloonTip(8000, "webpage commander is invoked via hotkey", "Press the hotkey (Alt + W) again to revoke", ToolTipIcon.Info);
Process.Start(Program.ProjectUrl + "/blob/master/webpage_commander.md");
}
}
}
}
return;
}
else if (m.Msg == 0x0010 || m.Msg == 0x0002)

View file

@ -21,15 +21,21 @@ namespace PersistentWindows.SystrayShell
public static System.Drawing.Icon BusyIcon = null;
public static System.Drawing.Icon UpdateIcon = null;
public static string AppdataFolder = null;
public static string DisableWebpageCommander = null;
public static string DisableUpgradeNotice = null;
public static string CmdArgs;
public static bool Gui = true;
public static bool hotkey_window = true;
public static uint hotkey = 'W'; //Alt + W
public static string WaitPwFinish = @":wait_to_finish
timeout /t 2 /nobreak >nul
tasklist | find ""PersistentWindows"" >nul
if not errorlevel 1 goto wait_to_finish";
private const int MaxSnapshots = 38; // 0-9, a-z, ` and final one for undo
static PersistentWindowProcessor pwp = null;
static SystrayForm systrayForm = null;
public static PersistentWindowProcessor pwp = null;
public static SystrayForm systrayForm = null;
static bool silent = false; //suppress all balloon tip & sound prompt
static bool notification = false; //pop balloon when auto restore
static int delay_manual_capture = 5000; //in millisecond
@ -50,9 +56,18 @@ namespace PersistentWindows.SystrayShell
pwp = new PersistentWindowProcessor();
var process = Process.GetCurrentProcess();
pwp.processPriority = process.PriorityClass;
process.PriorityClass = ProcessPriorityClass.High;
var timer = new System.Threading.Timer(state =>
{
process.PriorityClass = pwp.processPriority;
});
timer.Change(10000, System.Threading.Timeout.Infinite);
bool splash = true;
int delay_start = 0;
bool relaunch = false;
int delay_restart = 0;
int relaunch_delay = 0;
int delay_manual_capture = 0;
int delay_auto_capture = 0;
bool redirect_appdata = false; // use "." instead of appdata/local/PersistentWindows to store db file
@ -68,13 +83,16 @@ namespace PersistentWindows.SystrayShell
bool offscreen_fix = true;
bool fix_unminimized_window = true;
bool enhanced_offscreen_fix = false;
bool set_pos_match_threshold = false;
bool auto_restore_missing_windows = false;
bool auto_restore_from_db_at_startup = false;
bool auto_restore_last_capture_at_startup = false;
bool launch_once_per_process_id = true;
bool check_upgrade = true;
bool auto_upgrade = false;
bool legacy_icon = false;
bool waiting_taskbar = false;
int restore_snapshot = -1;
foreach (var arg in args)
{
@ -86,13 +104,12 @@ namespace PersistentWindows.SystrayShell
pwp.haltRestore = (Int32)(float.Parse(arg) * 1000);
continue;
}
else if (delay_start != 0)
else if (delay_restart != 0)
{
delay_start = 0;
delay_restart = 0;
if (!waiting_taskbar)
{
Thread.Sleep((Int32)(float.Parse(arg) * 1000));
relaunch = true;
relaunch_delay = (Int32)(float.Parse(arg));
}
continue;
}
@ -131,6 +148,17 @@ namespace PersistentWindows.SystrayShell
hotkey = arg[0];
continue;
}
else if (restore_snapshot != -1)
{
restore_snapshot = SnapshotCharToId(arg[0]);
continue;
}
else if (set_pos_match_threshold)
{
set_pos_match_threshold = false;
pwp.MaxDiffPos = int.Parse(arg);
continue;
}
switch(arg)
{
@ -153,8 +181,11 @@ namespace PersistentWindows.SystrayShell
case "-enable_auto_restore_by_manual_capture":
pwp.manualNormalSession = true;
break;
case "-delay_start":
delay_start = 1;
case "-fast_restore=0":
pwp.fastRestore = false;
break;
case "-delay_restart":
delay_restart = 1;
break;
case "-wait_taskbar":
waiting_taskbar = true;
@ -165,6 +196,9 @@ namespace PersistentWindows.SystrayShell
case "-delay_auto_capture":
delay_auto_capture = 1;
break;
case "-capture_floating_window=0":
pwp.captureFloatingWindow = false;
break;
case "-dpi_sensitive_call=1":
User32.DpiSenstiveCall = true;
break;
@ -199,7 +233,10 @@ namespace PersistentWindows.SystrayShell
fix_unminimized_window = false;
break;
case "-fix_taskbar=0":
pwp.fixTaskBar = false;
pwp.fixTaskBar = 0;
break;
case "-fix_taskbar_no_game":
pwp.fixTaskBar = -1;
break;
case "-foreground_background_dual_position=0":
pwp.enableDualPosSwitch = false;
@ -239,6 +276,15 @@ namespace PersistentWindows.SystrayShell
case "-redraw_desktop":
redraw_desktop = true;
break;
case "-auto_restore_existing_window_to_last_capture=1":
auto_restore_last_capture_at_startup = true;
break;
case "-auto_restore_new_window_to_last_capture=0":
pwp.autoRestoreNewWindowToLastCapture = false;
break;
case "-pos_match_threshold":
set_pos_match_threshold = true;
break;
case "-auto_restore_missing_windows":
case "-auto_restore_missing_windows=1":
auto_restore_missing_windows = true;
@ -251,7 +297,7 @@ namespace PersistentWindows.SystrayShell
auto_restore_missing_windows = true;
break;
case "-auto_restore_new_display_session_from_db=0":
pwp.autoRestoreLiveWindows = false;
pwp.autoRestoreLiveWindowsFromDb = false;
Log.Error("turn off auto restore db for new session");
break;
case "-invoke_multi_window_process_only_once=0":
@ -263,9 +309,21 @@ namespace PersistentWindows.SystrayShell
case "-auto_upgrade=1":
auto_upgrade = true;
break;
case "-dump_window_position_history=0":
pwp.dumpHistoryData = false;
break;
case "-restore_snapshot":
restore_snapshot = 0;
break;
}
}
if (restore_snapshot >= 0)
{
pwp.RestoreSnapshotCmd(restore_snapshot);
return;
}
string productName = System.Windows.Forms.Application.ProductName;
string appDataFolder = redirect_appdata ? "." :
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
@ -278,11 +336,18 @@ namespace PersistentWindows.SystrayShell
#endif
AppdataFolder = appDataFolder;
if (!Directory.Exists(appDataFolder))
Directory.CreateDirectory(appDataFolder);
DisableWebpageCommander = Path.Combine(AppdataFolder, "disable_webpage_commander");
DisableUpgradeNotice = Path.Combine(AppdataFolder, "disable_upgrade_notice");
// default icons
IdleIcon = legacy_icon ? Properties.Resources.pwIcon2 : Properties.Resources.pwIcon;
var iconHandle = Properties.Resources.pwIconBusy.GetHicon();
BusyIcon = legacy_icon ? Properties.Resources.pwIconBusy2 : System.Drawing.Icon.FromHandle(iconHandle);
iconHandle = Properties.Resources.pwIconUpdate.GetHicon();
var iconHandle = (legacy_icon ? Properties.Resources.pwIcon2: Properties.Resources.pwIcon).GetHicon();
IdleIcon = System.Drawing.Icon.FromHandle(iconHandle);
iconHandle = (legacy_icon ? Properties.Resources.pwIconBusy2 : Properties.Resources.pwIconBusy).GetHicon();
BusyIcon = System.Drawing.Icon.FromHandle(iconHandle);
iconHandle = (legacy_icon ? Properties.Resources.pwIconUpdate2 : Properties.Resources.pwIconUpdate).GetHicon();
UpdateIcon = System.Drawing.Icon.FromHandle(iconHandle);
// customized icon/png
@ -291,38 +356,49 @@ namespace PersistentWindows.SystrayShell
if (i == 1)
iconFolder = AppDomain.CurrentDomain.BaseDirectory;
string icon_path = Path.Combine(iconFolder, "pwIcon.ico");
string icon_png_path = Path.Combine(iconFolder, "pwIcon.png");
if (File.Exists(icon_png_path))
string ico_path = Path.Combine(iconFolder, "pwIcon.ico");
string png_path = Path.Combine(iconFolder, "pwIcon.png");
if (File.Exists(png_path))
{
var bitmap = new System.Drawing.Bitmap(icon_png_path); // or get it from resource
var bitmap = new System.Drawing.Bitmap(png_path);
IdleIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
}
else if (File.Exists(icon_path))
else if (File.Exists(ico_path))
{
IdleIcon = new System.Drawing.Icon(icon_path);
IdleIcon = new System.Drawing.Icon(ico_path);
}
icon_path = Path.Combine(iconFolder, "pwIconBusy.ico");
icon_png_path = Path.Combine(iconFolder, "pwIconBusy.png");
if (File.Exists(icon_png_path))
ico_path = Path.Combine(iconFolder, "pwIconBusy.ico");
png_path = Path.Combine(iconFolder, "pwIconBusy.png");
if (File.Exists(png_path))
{
var bitmap = new System.Drawing.Bitmap(icon_png_path);
var bitmap = new System.Drawing.Bitmap(png_path);
BusyIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
}
else if (File.Exists(icon_path))
else if (File.Exists(ico_path))
{
BusyIcon = new System.Drawing.Icon(icon_path);
BusyIcon = new System.Drawing.Icon(ico_path);
}
ico_path = Path.Combine(iconFolder, "pwIconUpdate.ico");
png_path = Path.Combine(iconFolder, "pwIconUpdate.png");
if (File.Exists(png_path))
{
var bitmap = new System.Drawing.Bitmap(png_path);
UpdateIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
}
else if (File.Exists(ico_path))
{
UpdateIcon = new System.Drawing.Icon(ico_path);
}
}
systrayForm = new SystrayForm();
systrayForm.enableUpgradeNotice = check_upgrade;
systrayForm = new SystrayForm(check_upgrade);
systrayForm.autoUpgrade = auto_upgrade;
if (relaunch)
if (relaunch_delay > 0)
{
Restart(2);
Restart(relaunch_delay);
return;
}
@ -363,10 +439,10 @@ namespace PersistentWindows.SystrayShell
if (ignore_process.Length > 0)
pwp.SetIgnoreProcess(ignore_process);
if (hotkey_window)
if (!File.Exists(DisableWebpageCommander) && hotkey_window)
HotKeyForm.Start(hotkey);
if (!pwp.Start(auto_restore_from_db_at_startup))
if (!pwp.Start(auto_restore_from_db_at_startup, auto_restore_last_capture_at_startup))
{
systrayForm.notifyIconMain.Visible = false;
return;
@ -401,17 +477,25 @@ namespace PersistentWindows.SystrayShell
Log.Error("taskbar not ready, restart PersistentWindows");
}
Restart(10);
Restart(1);
return false;
}
static void Restart(int delay)
static public void Restart(int delay, bool hidden = true)
{
Process p = new Process();
string batFile = Path.Combine(AppdataFolder, $"pw_restart.bat");
string content = $"timeout /t {delay} /nobreak > NUL";
string content = WaitPwFinish;
content += $"\ntimeout /t {delay} /nobreak > NUL";
content += "\nstart \"\" /B \"" + Path.Combine(Application.StartupPath, Application.ProductName) + ".exe\" " + "-wait_taskbar " + Program.CmdArgs;
File.WriteAllText(batFile, content);
Process.Start(batFile);
p.StartInfo.FileName = batFile;
if (hidden)
{
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.StartInfo.UseShellExecute = true;
}
p.Start();
Log.Error("program restarted");
}
@ -426,7 +510,9 @@ namespace PersistentWindows.SystrayShell
else
{
NotifyIcon ni = systrayForm.notifyIconMain;
ni.Icon = BusyIcon;
if (!systrayForm.toggleIcon) {
ni.Icon = BusyIcon;
}
if (silent)
return;
@ -451,7 +537,10 @@ namespace PersistentWindows.SystrayShell
else
{
NotifyIcon ni = systrayForm.notifyIconMain;
ni.Icon = IdleIcon;
if (!systrayForm.toggleIcon)
{
ni.Icon = IdleIcon;
}
if (Gui)
{
@ -775,5 +864,14 @@ namespace PersistentWindows.SystrayShell
Log.Error(format, args);
}
public static void WriteDataDump()
{
pwp.WriteDataDump();
}
public static void Stop()
{
pwp.Stop();
}
}
}

View file

@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("5.56.*")]
[assembly: AssemblyVersion("5.65.*")]

View file

@ -61,22 +61,22 @@ namespace PersistentWindows.SystrayShell.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Icon pwIcon {
internal static System.Drawing.Bitmap pwIcon {
get {
object obj = ResourceManager.GetObject("pwIcon", resourceCulture);
return ((System.Drawing.Icon)(obj));
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Icon pwIcon2 {
internal static System.Drawing.Bitmap pwIcon2 {
get {
object obj = ResourceManager.GetObject("pwIcon2", resourceCulture);
return ((System.Drawing.Icon)(obj));
return ((System.Drawing.Bitmap)(obj));
}
}
@ -91,12 +91,12 @@ namespace PersistentWindows.SystrayShell.Properties {
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Icon pwIconBusy2 {
internal static System.Drawing.Bitmap pwIconBusy2 {
get {
object obj = ResourceManager.GetObject("pwIconBusy2", resourceCulture);
return ((System.Drawing.Icon)(obj));
return ((System.Drawing.Bitmap)(obj));
}
}
@ -110,6 +110,16 @@ namespace PersistentWindows.SystrayShell.Properties {
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap pwIconUpdate2 {
get {
object obj = ResourceManager.GetObject("pwIconUpdate2", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>

View file

@ -119,20 +119,23 @@
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="pwIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\pwIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<value>..\Resources\pwIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="pwIcon2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\pwIcon2.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<value>..\Resources\pwIcon2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="pwIconBusy" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\pwIconBusy.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="pwIconBusy2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\pwIconBusy2.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
<value>..\Resources\pwIconBusy2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="pwIconUpdate" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\pwIconUpdate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="pwIconUpdate2" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\pwIconUpdate2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="question" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\question.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,123 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View file

@ -168,10 +168,6 @@ namespace PersistentWindows.SystrayShell
// pause/resume upgrade notice
//this.upgradeNoticeMenuItem.Text = "Disable upgrade notice";
this.upgradeNoticeMenuItem.Click += new System.EventHandler(this.PauseResumeUpgradeNotice);
if (this.enableUpgradeNotice)
this.upgradeNoticeMenuItem.Text = "Disable upgrade notice";
else
this.upgradeNoticeMenuItem.Text = "Enable upgrade notice";
//
// exitToolStripMenuItem

View file

@ -17,16 +17,11 @@ namespace PersistentWindows.SystrayShell
{
private const int MaxSnapshots = 38; // 0-9, a-z, ` and final one for undo
public bool restoreToolStripMenuItemEnabled;
public bool restoreSnapshotMenuItemEnabled;
private bool pauseAutoRestore = false;
private bool toggleIcon = false;
public bool toggleIcon = false;
public bool enableUpgradeNotice = true;
private int skipUpgradeCounter = 0;
private bool pauseUpgradeCounter = false;
private bool foundUpgrade = false;
public bool autoUpgrade = false;
@ -43,10 +38,25 @@ namespace PersistentWindows.SystrayShell
private Dictionary<string, bool> upgradeDownloaded = new Dictionary<string, bool>();
public SystrayForm()
public SystrayForm(bool enable_upgrade_notice)
{
InitializeComponent();
if (File.Exists(Program.DisableUpgradeNotice))
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
else if (!enable_upgrade_notice)
{
File.Create(Program.DisableUpgradeNotice);
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
}
else
upgradeNoticeMenuItem.Text = "Disable upgrade notice";
if (File.Exists(Program.DisableWebpageCommander))
{
invokeWebCommander.Text = "Enable webpage commander";
}
clickDelayTimer = new System.Timers.Timer(1000);
clickDelayTimer.Elapsed += ClickTimerCallBack;
clickDelayTimer.SynchronizingObject = this.contextMenuStripSysTray;
@ -166,7 +176,6 @@ namespace PersistentWindows.SystrayShell
ctrlKeyPressed = 0;
shiftKeyPressed = 0;
altKeyPressed = 0;
}
//private void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
@ -177,7 +186,7 @@ namespace PersistentWindows.SystrayShell
else
restoreToolStripMenuItem.Image = Properties.Resources.question;
if (checkUpgrade && enableUpgradeNotice)
if (checkUpgrade && upgradeNoticeMenuItem.Text.Contains("Disable"))
{
if (pauseUpgradeCounter)
{
@ -239,10 +248,21 @@ namespace PersistentWindows.SystrayShell
|| current_major == latest_major && current_minor < latest_minor)
{
notifyIconMain.ShowBalloonTip(5000, $"{Application.ProductName} {latestVersion} upgrade is available", "The upgrade notice can be disabled in menu", ToolTipIcon.Info);
foundUpgrade = true;
upgradeNoticeMenuItem.Text = $"Upgrade to {latestVersion}";
if (!upgradeDownloaded.ContainsKey(latestVersion))
{
string url = Program.ProjectUrl + "/releases";
var os_version = Environment.OSVersion;
if (os_version.Version.Major < 10)
Process.Start(url);
else if (os_version.Version.Build < 22000)
Process.Start(url);
/* windows 11
else
Process.Start(new ProcessStartInfo(url));
*/
var src_file = $"{Program.ProjectUrl}/releases/download/{latestVersion}/{System.Windows.Forms.Application.ProductName}{latestVersion}.zip";
var dst_file = $"{Program.AppdataFolder}/upgrade.zip";
var dst_dir = Path.Combine($"{Program.AppdataFolder}", "upgrade");
@ -256,7 +276,7 @@ namespace PersistentWindows.SystrayShell
upgradeDownloaded[latestVersion] = true;
string batFile = Path.Combine(Program.AppdataFolder, $"pw_upgrade.bat");
string content = "timeout /t 5 /nobreak > NUL";
string content = Program.WaitPwFinish;
content += $"\ncopy /Y \"{dst_dir}\\*.*\" \"{install_dir}\"";
content += "\nstart \"\" /B \"" + Path.Combine(install_dir, Application.ProductName) + ".exe\" " + Program.CmdArgs;
File.WriteAllText(batFile, content);
@ -264,10 +284,7 @@ namespace PersistentWindows.SystrayShell
if (autoUpgrade)
Upgrade();
else
{
upgradeNoticeMenuItem.Text = $"Upgrade to {latestVersion}";
notifyIconMain.Icon = Program.UpdateIcon;
}
}
}
}
@ -275,15 +292,24 @@ namespace PersistentWindows.SystrayShell
private void Exit()
{
#if DEBUG
var process = Process.GetCurrentProcess();
process.PriorityClass = ProcessPriorityClass.High;
Program.WriteDataDump();
Log.Event("Session exit");
this.notifyIconMain.Visible = false;
#endif
//this.notifyIconMain.Icon = null;
Log.Exit();
Program.Stop();
Application.Exit();
}
private void Upgrade()
{
Program.WriteDataDump();
string batFile = Path.Combine(Program.AppdataFolder, "pw_upgrade.bat");
Process.Start(batFile);
Exit();
@ -345,11 +371,21 @@ namespace PersistentWindows.SystrayShell
HotKeyForm.InvokeFromMenu();
else if (this.invokeWebCommander.Text.Contains("Disable"))
{
File.Create(Program.DisableWebpageCommander);
this.invokeWebCommander.Text = "Enable webpage commander";
HotKeyForm.Stop();
}
else
{
try
{
File.Delete(Program.DisableWebpageCommander);
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
this.invokeWebCommander.Text = "Disable webpage commander";
HotKeyForm.Start(Program.hotkey);
}
@ -394,20 +430,27 @@ namespace PersistentWindows.SystrayShell
private void PauseResumeUpgradeNotice(Object sender, EventArgs e)
{
if (foundUpgrade)
if (upgradeNoticeMenuItem.Text.Contains("Upgrade to"))
{
Upgrade();
}
else if (enableUpgradeNotice)
else if (upgradeNoticeMenuItem.Text.Contains("Enable"))
{
enableUpgradeNotice = false;
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
}
else
{
enableUpgradeNotice = true;
upgradeNoticeMenuItem.Text = "Disable upgrade notice";
CheckUpgradeSafe();
try
{
File.Delete(Program.DisableUpgradeNotice);
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
else //menu is "Disable upgrade notice"
{
File.Create(Program.DisableUpgradeNotice);
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
}
}
@ -418,6 +461,9 @@ namespace PersistentWindows.SystrayShell
private void ExitToolStripMenuItemClickHandler(object sender, EventArgs e)
{
bool ctrl_key_pressed = (User32.GetKeyState(0x11) & 0x8000) != 0;
if (ctrl_key_pressed)
Program.Restart(2, hidden:false);
Exit();
}

View file

@ -1,127 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="notifyIconMain.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="contextMenuStripSysTray.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>150, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</root>

View file

@ -52,7 +52,9 @@
</PropertyGroup>
<PropertyGroup />
<PropertyGroup />
<PropertyGroup />
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
@ -84,19 +86,12 @@
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="SplashForm.resx">
<DependentUpon>SplashForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="SystrayForm.resx">
<DependentUpon>SystrayForm.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<SubType>Designer</SubType>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="app.manifest" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@ -131,12 +126,6 @@
<ItemGroup>
<None Include="Resources\pwIconUpdate.png" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\pwIcon2.ico" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\pwIconBusy2.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>copy $(SolutionDir)*.bat $(TargetDir)

View file

@ -28,16 +28,16 @@
and Windows will automatically select the most compatible environment. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />

View file

@ -11,10 +11,11 @@ and restores back to its previous settings.
this tool and not have to worry about re-arranging when all is back to normal.
## Key Features
- Keeps track of window position changes, and automatically restores the desktop layout, including the taskbar position, to the last matching monitor setup.
- Auto restore: Keeps track of window position changes, and automatically restores the desktop layout, including the taskbar position, to the last matching monitor setup.
- Supports remote desktop sessions with multiple display configurations.
- Capture windows to disk: saves desktop layout capture to hard drive in liteDB format, so that closed windows can be restored after PC reboot, with virtual desktop observed.
- Capture snapshot to ram: saves desktop layout in memory using one char from [0-9a-z] as the name. The window Z-order is preserved in the snapshot.
- Capture windows to disk: manually saves desktop layout capture to hard drive in liteDB format, so that closed windows can be restored to corresponding virtual desktop after PC reboot.
- Capture snapshot: manually saves desktop layout to ram. The window Z-order is preserved in the snapshot. Up to 36 snapshots ([0-9a-z]) can be taken for each display configuration.
- Automatically persists the location history of all windows (alive and closed) to hard drive in xml format, so that manual-restore-point (aka snapshot) and auto-restore-point will continue to function smoothly upon app upgrade/restart, even after PC reboot.
- Webpage commander to improve the efficiency of web browsing for all major web browsers using one-letter commands like in vi editor.
- Efficient window switching between foreground and background dual positions.
- Pause/resume auto restore.
@ -28,11 +29,11 @@ this tool and not have to worry about re-arranging when all is back to normal.
> Note: the program can be run from any directory, but the program saves its data in
> *C:\Users\\[User]\AppData\Local\PersistentWindows*
**For PersistentWindows to be able to restore windows with elevated privileges (for tools like Task Manager or Event Viewer), it needs to be run with Administrator privileges.**
### To set up PersistentWindows to automatically start at user login:
This can be done by creating a task in **Task Scheduler**, or by adding a shortcut to the **Startup Folder** (shell:startup).
For PersistentWindows to be able to restore windows with elevated privileges (for tools like Task Manager or Event Viewer), it needs to be run with Administrator privileges.
Choose **one** of the three options:
**Task Scheduler (Windows 10/11)**

5
webpage_commander.md Normal file
View file

@ -0,0 +1,5 @@
### Webpage commander window is invoked via hotkey (Alt + W)
* If the invocation is unintentional, press the hotkey again to revoke webpage commander. The hotkey can be disabled via PW menu or command line.
* Webpage commander improves the efficiency of web browsing using single-letter command shortcut.
* Check out [Online Help](https://www.github.com/kangyu-california/PersistentWindows/blob/master/Help.md) for detailed instructions.