пятница, 8 августа 2014 г.

Виртуальный рабочий стол


Видеоприложение к публикации "Сергей Бадло. Игроки зазеркалья. Практические аспекты реализации виртуального рабочего стола. - DIGITAL KAZAKHSTAN, 2009, №10, с.40":


Как правило, когда работаешь на ПК/КПК одновременно с множеством приложений всегда не хватает рабочего пространства. Открыл Word, Photoshop, браузер, TheBat и Vegas Studio и вроде места уже нет. Хорошо, если на рабочем месте широкоформатный экран или есть дополнительный монитор и эта проблема решаема. А если вы в командировке с ноутбуком (нетбуком), то таскать за собой второй монитор по-меньшей мере неразумно и нецелесообразно. Вот если-бы иметь "виртуальный монитор" с быстрым переключением экранов… а еще лучше несколько. Спешим вас обрадовать, такие мониторы существуют и называются они – виртуальными рабочими столами (desktop - десктопами).

Рис. 1. "Несколько рабочих столов на одном мониторе? Проще простого…"

Краткий экскурс…

Что же такое – этот виртуальный рабочий стол? В сущности – это всего лишь программа, управляющая списком окон с управляемой видимостью в системе. Как и когда, определяет лишь сам пользователь.

Для создания виртуальных рабочих десктопов существует небольшое количество утилит - эмуляторов, таких как: BossKey, Aston, ManageDesk, WindowTool и др. Все они схожи между собой возможностями и почти одинаковы по функционалу, часть и просто с закрытыми исходниками, часть уже не поддерживаются. Рассмотрим вкратце характеристики некоторых из них:
BossKey 2.00
Достоинства: не требует инсталляции, настраиваемые горячие клавиши, малый размер (96кБ)
Недостатки: нет индивидуальной настройки каждого стола
Статус: бесплатный

Aston 1.91
Достоинства: индивидуальные настройки каждого стола, цветовые схемы, анимация, русский интерфейс
Недостатки: высокие требования к ресурсам, требует инсталляции, ”глюки” при настройке
Статус: платный

VirtuaWin
Достоинства: множество настроек, переключение курсором.
Недостатки: загнулся оффресурс
Статус: бесплатная

ManageDesk 2.30
Достоинства: дополнительные функции по управлению системой, как-то CD-ROM, выключение компьютера
Недостатки: требует инсталляции
Статус: платный

WindowTool1.3
Достоинства: настраиваемые окна
Недостатки: требует инсталляции
Статус: бесплатный

Cool Desk 3.86
Достоинства: индивидуальные настройки окон и клавиш горячего вызова, создание до 9 десктопов
Недостатки: требует инсталляции
Статус: бесплатный
Предпосылки реализации ПО. Возможные решения

Вы уже задаетесь вопросом, какова-же основная идея создания нашего "виртуального" рабочего стола? Все достаточно просто. Как известно, все в Windows- системе является процессами. Каждый из текущих процессов может порождать окна. Сами окна могут находиться как в минимизированном, свернутом, так и невидимом состоянии. Вот это-то свойство окон и положено в основу алгоритма программы. Представьте себе, что вы запомнили список всех видимых окон на данный текущий момент, а потом сделали их все – невидимыми (hidden). Что произойдет? По сути – ваш рабочий стол очистится и будет свободно пространство для открытия еще окон приложений. А что-же будет, если мы после этого откроем еще n- количество новых приложений, сделаем их невидимыми и опять сохраним новый список паралельно со старым? Правильно, мы получим опять "чистый" рабочий стол. Где-же, снова спросите вы, "виртуальные" рабочие столы? Да вот-же, вспомните, что мы сохраняли каждый раз списки окон перед тем как делать их невидимыми. Следовательно, если с помощью некоего интерфейса управления каждый раз восстанавливать (делать видимыми) наши сохраненные списки, то мы будем тем самым переключаться как-бы между рабочими столами… новыми и новыми.

Конечно-же, у этого способа есть свои ограничения, такие как один и тот-же фон рабочего стола и то-же количество и расположение системных и пользовательских иконок, НО… нам ведь никто не мешает добавить сохранение списков фонов, заставок, режимов монитора, иконок рабочих столов и прочее, и восстанавливать каждый раз их индивидуальные настройки.

Таким образом, мы уже можем определить основные требования к "виртуальному" столу:
  • возможность получения списка хэндлов* всех видимых окон в системе
  • сохранение (скрытие) и восстановление (визуализация) списка окон открытых для каждого режима
  • удобный интерфейс управления
  • возможность переключения между рабочими столами по горячей клавише
  • открытые исходники
* хэндл (handle) – это идентификатор каждого окна (процесса) в системе, с помощью него можно получить управление для данного конкретного окна
Практика. Виртуальный рабочий стол

Итак, приступим к основной задаче. Для работы нам понадобится следующее:
  • среда TDL portable
  • среда исполнения Win 98/NT/XP/7/различные эмуляторы, типа WinE)
Так как наше приложение не будет иметь никаких интерфейсных окон и будет реализовано на WinAPI, то целесообразно все управление поместить в трей по иконке на каждый рабочий стол. Рассмотрим основные моменты в алгоритме управления и взаимодействия.

Прежде всего, введем** n-m- мерные массивы для хранения хэндлов списка окон каждого из "виртуальных" рабочих столов: pid, pid1, pid2, pid3, pid4, pid5: array of array of integer; // массив массивов.
** это нужно для того, чтобы знать - какое из окон приложений в системе было открыто или свернуто в каждом из выбранных режимов
Переберем хэндлы всех видимых окон приложений (кроме свернутых в иконку трея):
procedure get_pid; // получение текущего списка открытых окон в системе
var
 wnd : hWnd;
 buff: array [0..127] of Char;
begin
 setlength(pid,0,0);
 //
 wnd:= GetWindow(Handle, gw_HWndFirst);
 while wnd <> 0 do begin
  if (wnd <> Handle) and            // свое окно
     IsWindowVisible(wnd) and       // невидимые окна
     (GetWindow(wnd, gw_Owner) = 0) and // дочерние окна
     (GetWindowText(wnd, buff, sizeof(buff)) <> 0)
  then begin
   GetWindowText(wnd, buff, sizeof(buff));
   if lowercase(strpas(buff))<>'program manager' then begin //отсекаем окно панели программ
    setlength(pid,length(pid)+1,length(pid)+1);
    pid[length(pid)-1,0]:= wnd;
    pid[length(pid)-1,1]:= longint(IsIconic(wnd))
   end
  end;

  wnd:= GetWindow(wnd, gw_hWndNext)
 end
end;
Логику управления и переключения десктопов достаточно просто реализовать, зная текущий выбор пользователя из меню (или по горячей клавише) и восстанавливая при этом предыдущий сохраненный для этого состояния список окон. Для чего сохраняем в каждом из массивов хэндлы и состояние окон (свернуто-развернуто) при смене режима:
{ основной алгоритм переключения виртуальных столов }

// триггер столов-

procedure select(n: smallint);
var i: integer;
begin
 glw:= n; // синхронизация
 if glw_temp=n then exit;
 //
 case n of // управление иконками в режимах
  0: begin set_tn(2,1,0,hint); set_tn(2,1,1,hint); set_tn(2,1,2,hint); set_tn(2,1,3,hint); set_tn(0,1,4,hint) end; //12220
  1: begin set_tn(2,1,0,hint); set_tn(2,1,1,hint); set_tn(2,1,2,hint); set_tn(0,1,3,hint); set_tn(1,1,4,hint) end; //12202
  2: begin set_tn(2,1,0,hint); set_tn(2,1,1,hint); set_tn(0,1,2,hint); set_tn(2,1,3,hint); set_tn(1,1,4,hint) end; //12022
  3: begin set_tn(2,1,0,hint); set_tn(0,1,1,hint); set_tn(2,1,2,hint); set_tn(2,1,3,hint); set_tn(1,1,4,hint) end; //10222
  4: begin set_tn(0,1,0,hint); set_tn(2,1,1,hint); set_tn(2,1,2,hint); set_tn(2,1,3,hint); set_tn(1,1,4,hint) end  //02222
 end;

 //скрыть текущие-
 get_pid;
 if n<>-1 then
  for i:=0 to length(pid)-1 do begin
   sendMessage(pid[i,0], WM_SYSCOMMAND, SC_MINIMIZE, 0);
   showwindow(pid[i,0], sw_hide)
  end;

// восстановить предыдущие-
case n of
  0:  for i:=length(pid1)-1 downto 0 do begin
       showwindow(pid1[i,0],SW_SHOW);
       if pid1[i,1]=0 then
        sendMessage(pid1[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
      end;
  1:  for i:=length(pid2)-1 downto 0 do begin
       showwindow(pid2[i,0],SW_SHOW);
       if pid2[i,1]=0 then
        sendMessage(pid2[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
      end;
  2:  for i:=length(pid3)-1 downto 0 do begin
       showwindow(pid3[i,0],SW_SHOW);
       if pid3[i,1]=0 then
        sendMessage(pid3[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
      end;
  3:  for i:=length(pid4)-1 downto 0 do begin
       showwindow(pid4[i,0],SW_SHOW);
       if pid4[i,1]=0 then
        sendMessage(pid4[i,0],WM_SYSCOMMAND,SC_RESTORE,0);
      end;
  4:  for i:=length(pid5)-1 downto 0 do begin
       showwindow(pid5[i,0],SW_SHOW);
       if pid5[i,1]=0 then
        sendMessage(pid5[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
      end;
  -1: begin // все-
       for i:=length(pid1)-1 downto 0 do begin
        showwindow(pid1[i,0],SW_SHOW);
        sendMessage(pid1[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
       end;
       for i:=length(pid2)-1 downto 0 do begin
        showwindow(pid2[i,0],SW_SHOW);
        sendMessage(pid2[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
       end;
       for i:=length(pid3)-1 downto 0 do begin
        showwindow(pid3[i,0],SW_SHOW);
        sendMessage(pid3[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
       end;
       for i:=length(pid4)-1 downto 0 do begin
        showwindow(pid4[i,0],SW_SHOW);
        sendMessage(pid4[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
       end;
       for i:=length(pid5)-1 downto 0 do begin
        showwindow(pid5[i,0],SW_SHOW);
        sendMessage(pid5[i,0],WM_SYSCOMMAND,SC_RESTORE,0)
       end;
      end
 end;
Реализация управления через трей и горячую клавишу:
{ обработка событий нажатий в трее и горячей клавишы }

// обработка прерываний-

function WndProc(hnd, wmsg, wparam, lparam: integer): integer; stdcall;

 procedure down(lparam,n: integer);
 begin
  case lparam of
   WM_LBUTTONdblCLK:;
   WM_MBUTTONDOWN  : exito;
   WM_LBUTTONDOWN  :;
   WM_LBUTTONUP : select(n); //переключение-
   WM_RBUTTONUP : begin
                      SetForegroundWindow(hnd);
                      if (PopupMenu<>0) then MakeTrayPopup(lparam)
                     end;
  end
 end;

var n : Integer;
    TrayPopup : Boolean;
begin
 TrayPopup:= PopupMenu<>0;

 case wmsg of
  // переключение между столами-
  WM_HOTKEY: begin
              inc(glw); if glw>4 then glw:= 0;
              select(glw)
             end;

  WM_COMMAND : If (TrayPopup) then for n:= 0 to MItemCount-1 do
                                    if MenuKeys[n]=lparam then TrayProc(dword(wparam));

  // обработка каждого callback
  WM_USER + 222+0: down(dword(lparam),4); //нажатия на 1-ю иконку
  WM_USER + 222+1: down(dword(lparam),3); //…2
  WM_USER + 222+2: down(dword(lparam),2); //…3
  WM_USER + 222+3: down(dword(lparam),1); //…4
  WM_USER + 222+4: down(dword(lparam),0); //…5

  WM_DESTROY: exito;
  else Result:= DefWindowProc(hnd, wmsg, wparam, lparam)          
 end
end;
И конечно-же, отображение управляющей части в трее:
{ создание и отображение n- иконок в трее }

// модуль ресурсных иконок + hint

procedure set_tn(ti,r,n: smallint; hint:shortstring);
begin
 IconData.cbSize:= SizeOf(IconData);
 IconData.Wnd   := Handle;
 //
 IconData.uID   := n; // n- иконка
 IconData.uFlags:= NIF_ICON or NIF_MESSAGE or NIF_TIP;
 IconData.uCallbackMessage:= WM_USER + 222+n; // TRAY_CALLBACK; //n- callback
 case ti of
  0: IconData.hIcon:= loadicon(HInstance, 'pn');
  1: IconData.hIcon:= loadicon(HInstance, 'pm');
  2: IconData.hIcon:= loadicon(HInstance, 'pw')
 end;

 StrPLCopy(IconData.szTip,hint+' '+inttostr(4-n+1),SizeOf(IconData.szTip)-1);

 if r=0 then begin                                 //-add
  Shell_NotifyIcon(NIM_ADD, @IconData);
  tmr1:= timesetevent(250,0,@Ontmr1,0,TIME_PERIODIC)
 end;
 if r=1 then Shell_NotifyIcon(NIM_MODIFY, @IconData);//-mod
 if r=2 then begin                                 //-del
  timeKillEvent(tmr1);
  //DeallocateHWnd(IconData.Wnd);
  Shell_NotifyIcon(NIM_DELETE, @IconData)
 end
end;
В результате компиляции проекта, в трее появятся 5- зеленых иконок нашего приложения (см. рис.2):


Рис. 2. Основной рабочий стол

Переключив горячей клавишей или мышкой через меню в трее на второй и третий рабочий стол и т.д, мы можем запускать новые и новые приложения совершенно не мешающие друг другу (см. рис. 3):

 
Рис. 3. Переключение между виртуальными рабочими столами (TheBat, Word и переводчик Promt)

Заключение

Вы можете ограничить количество отбражаемых иконок путем исключения лишних процедур set_tn() при создании приложения. Каждая из иконок отвечает за соответствующий рабочий стол. При этом смена режима возможна как циклически по горячей клавише "Win"+"1", так и по выбору пользователя щелчком левой кнопкой мыши по иконкам, либо правой кнопкой через меню.

скачать

Комментариев нет:

Отправить комментарий

В комментариях уважайте собеседника, внимательно читайте посты и не додумывайте. Просьбы и предложения из разряда: «можно ваш Skype/Viber/телефон», «напишите мне в vk/FB», а также другие им подобные — игнорируются. Выход новых версий ПО, внешняя ссылка, переставшая работать с течением времени и т.п. не является основанием для претензий. Желающие спокойно подискутировать и высказаться — Welcome. Желающие спонсировать блог — Donate. Нарушение этих простых правил ведет к бану и удалению комментариев без предупреждения.