1 /*
2 * IceWM
3 *
4 * Copyright (C) 1997-2002 Marko Macek
5 *
6 * TaskBar
7 */
8
9 #include "config.h"
10 #include "wmtaskbar.h"
11 #include "wmframe.h"
12 #include "wmmgr.h"
13 #include "wmconfig.h"
14 #include "wmprog.h"
15 #include "wmwinmenu.h"
16 #include "wmapp.h"
17 #include "wmwinlist.h"
18 #include <unistd.h>
19
20 #include "aaddressbar.h"
21 #include "aclock.h"
22 #include "akeyboard.h"
23 #include "acpustatus.h"
24 #include "amemstatus.h"
25 #include "apppstatus.h"
26 #include "amailbox.h"
27 #include "objbar.h"
28 #include "objbutton.h"
29 #include "atasks.h"
30 #include "atray.h"
31 #include "aworkspaces.h"
32 #include "yxtray.h"
33 #include "prefs.h"
34 #include "yprefs.h"
35 #include "wpixmaps.h"
36 #include "aapm.h"
37
38 #include "intl.h"
39
40 TaskBar *taskBar;
41
42 YColorName taskBarBg(&clrDefaultTaskBar);
43
EdgeTrigger(TaskBar * owner)44 EdgeTrigger::EdgeTrigger(TaskBar *owner):
45 fTaskBar(owner),
46 fHideOrShow(Hide)
47 {
48 setStyle(wsOverrideRedirect | wsInputOnly);
49 setPointer(YWMApp::leftPointer);
50 setDND(enabled());
51 setTitle("IceEdge");
52 }
53
~EdgeTrigger()54 EdgeTrigger::~EdgeTrigger() {
55 }
56
startTimer(HideOrShow show)57 void EdgeTrigger::startTimer(HideOrShow show) {
58 fHideOrShow = show;
59 long delay = max(10, show ? autoShowDelay : autoHideDelay);
60 fAutoHideTimer->setTimer(delay, this, true);
61 }
62
stopTimer()63 void EdgeTrigger::stopTimer() {
64 fHideOrShow = Hide;
65 fAutoHideTimer = null;
66 }
67
enabled()68 bool EdgeTrigger::enabled() {
69 return (taskBarAutoHide | (taskBarFullscreenAutoShow & !taskBarKeepBelow));
70 }
71
show(bool enable)72 void EdgeTrigger::show(bool enable) {
73 bool enabled(this->enabled());
74 if (enable && enabled) {
75 YWindow::show();
76 } else {
77 YWindow::hide();
78 if (enabled) {
79 startTimer();
80 }
81 }
82 }
83
handleCrossing(const XCrossingEvent & crossing)84 void EdgeTrigger::handleCrossing(const XCrossingEvent &crossing) {
85 if (crossing.type == EnterNotify /* && crossing.mode != NotifyNormal */) {
86 unsigned long last = YWindow::getLastEnterNotifySerial();
87 if (crossing.serial != last && crossing.serial != last + 1) {
88 MSG(("enter notify %d %d", crossing.mode, crossing.detail));
89 startTimer(Show);
90 }
91 } else if (crossing.type == LeaveNotify /* && crossing.mode != NotifyNormal */) {
92 MSG(("leave notify"));
93 stopTimer();
94 }
95 }
96
handleDNDEnter()97 void EdgeTrigger::handleDNDEnter() {
98 startTimer(Show);
99 }
100
handleDNDLeave()101 void EdgeTrigger::handleDNDLeave() {
102 startTimer();
103 }
104
handleTimer(YTimer * t)105 bool EdgeTrigger::handleTimer(YTimer *t) {
106 MSG(("taskbar handle timer"));
107 return fTaskBar->autoTimer(fHideOrShow);
108 }
109
TaskBar(IApp * app,YWindow * aParent,YActionListener * wmActionListener,YSMListener * smActionListener)110 TaskBar::TaskBar(IApp *app, YWindow *aParent, YActionListener *wmActionListener, YSMListener *smActionListener):
111 YFrameClient(aParent, nullptr),
112 fSurface(taskBarBg, taskbackPixmap, taskbackPixbuf),
113 fTasks(nullptr),
114 fCollapseButton(nullptr),
115 fWindowTray(nullptr),
116 fKeyboardStatus(nullptr),
117 fMailBoxControl(nullptr),
118 fMEMStatus(nullptr),
119 fCPUStatus(nullptr),
120 fApm(nullptr),
121 fNetStatus(nullptr),
122 fObjectBar(nullptr),
123 fApplications(nullptr),
124 fWinList(nullptr),
125 fShowDesktop(nullptr),
126 fAddressBar(nullptr),
127 fWorkspaces(nullptr),
128 fDesktopTray(nullptr),
129 fEdgeTrigger(nullptr),
130 wmActionListener(wmActionListener),
131 smActionListener(smActionListener),
132 app(app),
133 fIsHidden(taskBarAutoHide),
134 fFullscreen(false),
135 fIsCollapsed(false),
136 fMenuShown(false),
137 fNeedRelayout(true),
138 fButtonUpdate(false),
139 fWorkspacesUpdate(false)
140 {
141 taskBar = this;
142
143 addStyle(wsDesktopAware | wsTakeFocus | wsNoExpose);
144 setWinHintsHint(WinHintsSkipFocus |
145 WinHintsSkipWindowMenu |
146 WinHintsSkipTaskBar);
147
148 setWorkspaceHint(AllWorkspaces);
149 updateWinLayer();
150 Atom protocols[2] = {
151 _XA_WM_DELETE_WINDOW,
152 _XA_WM_TAKE_FOCUS
153 };
154 XSetWMProtocols(xapp->display(), handle(), protocols, 2);
155 XWMHints wmhints = { InputHint, False, };
156 ClassHint clhint("icewm", "TaskBar");
157 YTextProperty text("TaskBar");
158 XSetWMProperties(xapp->display(), handle(), &text, &text,
159 nullptr, 0, nullptr, &wmhints, &clhint);
160 setNetPid();
161
162 setMwmHints(MwmHints(
163 MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS,
164 MWM_FUNC_MOVE));
165 setFrameState(NormalState);
166 setPointer(YWMApp::leftPointer);
167 setDND(true);
168
169 fEdgeTrigger = new EdgeTrigger(this);
170
171 initApplets();
172
173 MSG(("taskbar"));
174 }
175
~TaskBar()176 TaskBar::~TaskBar() {
177 detachDesktopTray();
178 delete fEdgeTrigger; fEdgeTrigger = nullptr;
179 delete fClock; fClock = nullptr;
180 delete fKeyboardStatus; fKeyboardStatus = nullptr;
181 delete fMailBoxControl; fMailBoxControl = nullptr;
182 #ifdef MEM_STATES
183 delete fMEMStatus; fMEMStatus = nullptr;
184 #endif
185 delete fWinList; fWinList = nullptr;
186 delete fApplications; fApplications = nullptr;
187 delete fObjectBar; fObjectBar = nullptr;
188 delete fWorkspaces; fWorkspaces = nullptr;
189 #ifdef MAX_ACPI_BATTERY_NUM
190 delete fApm; fApm = nullptr;
191 #endif
192 #ifdef IWM_STATES
193 delete fCPUStatus; fCPUStatus = nullptr;
194 #endif
195 delete fNetStatus; fNetStatus = nullptr;
196 delete fAddressBar; fAddressBar = nullptr;
197 delete fTasks; fTasks = nullptr;
198 delete fWindowTray; fWindowTray = nullptr;
199 delete fCollapseButton; fCollapseButton = nullptr;
200 delete fShowDesktop; fShowDesktop = nullptr;
201 xapp->dropClipboard();
202 taskBar = nullptr;
203 if (getFrame())
204 getFrame()->unmanage(false);
205 MSG(("taskBar delete"));
206 }
207
208 class TaskBarMenu : public YMenu {
209 public:
updatePopup()210 void updatePopup() {
211 if (0 < itemCount())
212 return;
213
214 setActionListener(taskBar);
215 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
216 addItem(_("Tile _Vertically"), -2, KEY_NAME(gKeySysTileVertical), actionTileVertical);
217 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
218 addItem(_("T_ile Horizontally"), -2, KEY_NAME(gKeySysTileHorizontal), actionTileHorizontal);
219 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
220 addItem(_("Ca_scade"), -2, KEY_NAME(gKeySysCascade), actionCascade);
221 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
222 addItem(_("_Arrange"), -2, KEY_NAME(gKeySysArrange), actionArrange);
223 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
224 addItem(_("_Minimize All"), -2, KEY_NAME(gKeySysMinimizeAll), actionMinimizeAll);
225 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
226 addItem(_("_Hide All"), -2, KEY_NAME(gKeySysHideAll), actionHideAll);
227 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
228 addItem(_("_Undo"), -2, KEY_NAME(gKeySysUndoArrange), actionUndoArrange);
229 if (minimizeToDesktop)
230 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
231 addItem(_("Arrange _Icons"), -2, KEY_NAME(gKeySysArrangeIcons), actionArrangeIcons);
232 addSeparator();
233 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
234 addItem(_("_Windows"), -2, actionWindowList, windowListMenu);
235 addSeparator();
236 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
237 addItem(_("_Refresh"), -2, null, actionRefresh);
238 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
239 addItem(_("_About"), -2, actionAbout, nullptr);
240 if (showLogoutMenu) {
241 addSeparator();
242 if (showLogoutSubMenu)
243 // TRANSLATORS: This appears in a group with others items, so please make the hotkeys unique in the set: # T_ile Horizontally, Ca_scade, _Arrange, _Minimize All, _Hide All, _Undo, Arrange _Icons, _Windows, _Refresh, _About, _Logout
244 addItem(_("_Logout..."), -2, actionLogout, logoutMenu);
245 else
246 addItem(_("_Logout..."), -2, null, actionLogout);
247 }
248
249 setTitle("IceMenu");
250 setClassHint("icemenu", "TaskBar");
251 setNetWindowType(_XA_NET_WM_WINDOW_TYPE_POPUP_MENU);
252 }
253 };
254
initApplets()255 void TaskBar::initApplets() {
256 #ifdef MEM_STATES
257 if (taskBarShowMEMStatus)
258 fMEMStatus = new MEMStatus(this, this);
259 else
260 fMEMStatus = nullptr;
261 #endif
262
263 #ifdef IWM_STATES
264 if (taskBarShowCPUStatus)
265 fCPUStatus = new CPUStatusControl(smActionListener, this, this);
266 else
267 fCPUStatus = nullptr;
268 #endif
269
270 if (taskBarShowNetStatus)
271 fNetStatus = new NetStatusControl(app, smActionListener, this, this);
272 else
273 fNetStatus = nullptr;
274
275 if (taskBarShowClock)
276 fClock = new ClockSet(smActionListener, this, this);
277 else
278 fClock = nullptr;
279
280 #ifdef MAX_ACPI_BATTERY_NUM
281 if (taskBarShowApm && (access(APMDEV, 0) == 0 ||
282 access("/sys/class/power_supply", 0) == 0 ||
283 access("/proc/acpi", 0) == 0 ||
284 access("/dev/acpi", 0) == 0 ||
285 access("/proc/pmu", R_OK|X_OK) == 0))
286 {
287 fApm = new YApm(this);
288 fApm->setTitle("IceAPM");
289 }
290 else if (!taskBarShowApm && taskBarShowApmAuto)
291 {
292 fApm = new YApm(this, true);
293 if ( ! fApm->hasBatteries()) {
294 delete fApm;
295 fApm = nullptr;
296 }
297 else fApm->setTitle("IceAPM");
298 }
299 else
300 fApm = nullptr;
301 #endif
302
303 if (taskBarShowCollapseButton) {
304 fCollapseButton = new ObjectButton(this, actionCollapseTaskbar);
305 if (fCollapseButton) {
306 fCollapseButton->setWinGravity(StaticGravity);
307 ref<YImage> image = leftToRight
308 ? taskbarCollapseImage : taskbarExpandImage;
309 if (image != null) {
310 fCollapseButton->setImage(image);
311 } else {
312 fCollapseButton->setText(leftToRight ? ">" : "<");
313 }
314 fCollapseButton->setActionListener(this);
315 fCollapseButton->setToolTip(_("Hide Taskbar"));
316 fCollapseButton->setTitle("Collapse");
317 }
318 } else
319 fCollapseButton = nullptr;
320
321 if (taskBarShowMailboxStatus) {
322 fMailBoxControl = new MailBoxControl(app, smActionListener, this, this);
323 } else
324 fMailBoxControl = nullptr;
325
326 if (configKeyboards.nonempty()) {
327 fKeyboardStatus = new KeyboardStatus(wmapp, this, this);
328 } else
329 fKeyboardStatus = nullptr;
330
331 if (taskBarShowStartMenu) {
332 class LazyRootMenu : public LazyMenu {
333 YMenu* ymenu() { return rootMenu; }
334 };
335 fApplications = new ObjectButton(this, new LazyRootMenu);
336 fApplications->setActionListener(this);
337 fApplications->setImage(taskbarStartImage);
338 fApplications->setToolTip(_("Favorite Applications"));
339 fApplications->setTitle("TaskBarMenu");
340 } else
341 fApplications = nullptr;
342
343 fObjectBar = new ObjectBar(this);
344 if (fObjectBar) {
345 upath t = app->findConfigFile("toolbar");
346 if (t != null) {
347 MenuLoader(app, smActionListener, wmActionListener)
348 .loadMenus(t, fObjectBar);
349 }
350 if (fObjectBar->nonempty()) {
351 fObjectBar->setTitle("IceToolbar");
352 } else {
353 delete fObjectBar; fObjectBar = nullptr;
354 }
355 }
356 if (taskBarShowWindowListMenu) {
357 class LazyWindowListMenu : public LazyMenu {
358 YMenu* ymenu() { return windowListMenu; }
359 };
360 fWinList = new ObjectButton(this, new LazyWindowListMenu);
361 fWinList->setImage(taskbarWindowsImage);
362 fWinList->setActionListener(this);
363 fWinList->setToolTip(_("Window List Menu"));
364 fWinList->setTitle("ShowWindowList");
365 } else
366 fWinList = nullptr;
367 if (taskBarShowShowDesktopButton) {
368 fShowDesktop = new ObjectButton(this, actionShowDesktop);
369 fShowDesktop->setText("__");
370 fShowDesktop->setImage(taskbarShowDesktopImage);
371 fShowDesktop->setActionListener(wmActionListener);
372 fShowDesktop->setToolTip(_("Show Desktop"));
373 fShowDesktop->setTitle("ShowDesktop");
374 }
375
376 fWorkspaces = taskBarShowWorkspaces
377 ? new WorkspacesPane(this)
378 : new AWorkspaces(this);
379 fWorkspaces->setTitle("Workspaces");
380
381 if (enableAddressBar) {
382 fAddressBar = new AddressBar(app, this);
383 fAddressBar->setTitle("AddressBar");
384 }
385 if (taskBarShowWindows) {
386 fTasks = new TaskPane(this, this);
387 fTasks->setTitle("TaskPane");
388 } else
389 fTasks = nullptr;
390 if (taskBarShowTray) {
391 fWindowTray = new TrayPane(this, this);
392 fWindowTray->setTitle("TrayPane");
393 } else
394 fWindowTray = nullptr;
395
396 if (taskBarEnableSystemTray) {
397 const char atomstr[] =
398 #ifdef CONFIG_EXTERNAL_TRAY
399 "_ICEWM_INTTRAY_S"
400 #else
401 "_NET_SYSTEM_TRAY_S"
402 #endif
403 ;
404 YAtom trayatom(atomstr, true);
405 bool isInternal = ('I' == atomstr[1]);
406
407 fDesktopTray = new YXTray(this, isInternal, trayatom,
408 this, trayDrawBevel);
409 fDesktopTray->setTitle("SystemTray");
410 fDesktopTray->relayout();
411 } else {
412 fDesktopTray = nullptr;
413 updateLocation();
414 }
415
416 if (fCollapseButton) {
417 fCollapseButton->raise();
418 }
419 }
420
trayChanged()421 void TaskBar::trayChanged() {
422 relayout();
423 }
424
425 struct LayoutInfo {
426 YWindow *w;
427 bool left;
428 bool row; // 0 = bottom, 1 = top
429 bool show;
430 bool expand;
431 short pre, post;
432
LayoutInfoLayoutInfo433 LayoutInfo() :
434 w(nullptr), left(false), row(false), show(false),
435 expand(false), pre(0), post(0) {}
LayoutInfoLayoutInfo436 LayoutInfo(YWindow *w, bool l, bool r, bool s, bool e, short p, short o) :
437 w(w), left(l), row(r), show(s), expand(e), pre(p), post(o) {}
438 };
439
updateLayout(unsigned & size_w,unsigned & size_h)440 void TaskBar::updateLayout(unsigned &size_w, unsigned &size_h) {
441 enum { Over, Here };
442 enum { Bot, Top };
443 enum { Same, Show };
444 enum { Keep, Grow };
445 LayoutInfo nw;
446 YArray<LayoutInfo> wlist(16);
447
448 bool issue314 = taskBarAtTop;
449 nw = LayoutInfo( fApplications, Here, issue314, Show, Grow, 0, 0 );
450 wlist.append(nw);
451 if (taskBarShowShowDesktopButton == 1) {
452 nw = LayoutInfo( fShowDesktop, Here, !issue314, Show, Grow, 0, 0 );
453 wlist.append(nw);
454 }
455 nw = LayoutInfo( fWinList, Here, !issue314, Show, Grow, 0, 0 );
456 wlist.append(nw);
457 nw = LayoutInfo( fObjectBar, Here, Top, Show, Grow, 4, 0 );
458 wlist.append(nw);
459 nw = LayoutInfo( fCollapseButton, Over, Bot, Show, Grow, 0, 2 );
460 wlist.append(nw);
461 nw = LayoutInfo( fWorkspaces, taskBarWorkspacesLeft,
462 taskBarDoubleHeight && taskBarWorkspacesTop,
463 taskBarShowWorkspaces && workspaceCount > 0,
464 Grow, 4, 4 );
465 wlist.append(nw);
466
467 if (taskBarShowShowDesktopButton == 2) {
468 nw = LayoutInfo( fShowDesktop, Over, Top, Show, Keep, 1, 1);
469 wlist.append(nw);
470 }
471
472 if (fClock) {
473 for (YClock* clock : *fClock) {
474 wlist += LayoutInfo( clock, Over, Top, Same, Keep, 2, 2 );
475 }
476 }
477
478 if (taskBarShowMailboxStatus) {
479 for (auto m = fMailBoxControl->iterator(); ++m; ) {
480 nw = LayoutInfo( *m, Over, Top, Show, Keep, 1, 1 );
481 wlist.append(nw);
482 }
483 }
484 if (fKeyboardStatus) {
485 nw = LayoutInfo( fKeyboardStatus, Over, Top, Show, Keep, 1, 1 );
486 wlist.append(nw);
487 }
488
489 #ifdef IWM_STATES
490 if (taskBarShowCPUStatus) {
491 auto it = fCPUStatus->getIterator();
492 while (++it)
493 {
494 nw = LayoutInfo(*it, Over, Top, Show, Keep, 2, 2 );
495 wlist.append(nw);
496 }
497 }
498 #endif
499
500 #ifdef MEM_STATES
501 nw = LayoutInfo( fMEMStatus, Over, Top, Same, Keep, 2, 2 );
502 wlist.append(nw);
503 #endif
504
505 if (taskBarShowNetStatus) {
506 auto it = fNetStatus->getIterator();
507 while (++it)
508 {
509 if (*it != 0) {
510 nw = LayoutInfo(*it, Over, Top, Same, Keep, 2, 2 );
511 wlist.append(nw);
512 }
513 }
514 }
515 #ifdef MAX_ACPI_BATTERY_NUM
516 nw = LayoutInfo( fApm, Over, Top, Show, Keep, 0, 2 );
517 wlist.append(nw);
518 #endif
519 nw = LayoutInfo( fDesktopTray, Over, Top, Show, Keep, 1, 1 );
520 wlist.append(nw);
521 nw = LayoutInfo( fWindowTray, Over, Bot, Show, Grow, 1, 1 );
522 wlist.append(nw);
523 const int wcount = wlist.getCount();
524
525 int y[2] = { 0, 0 };
526 unsigned h[2] = { 0, 0 };
527 int left[2] = { 0, 0 };
528 int right[2] = { 0, 0 };
529
530 if (!taskBarDoubleHeight)
531 for (int i = 0; i < wcount; i++)
532 wlist[i].row = false;
533 for (int i = 0; i < wcount; i++) {
534 if (wlist[i].w) {
535 if (h[wlist[i].row] < wlist[i].w->height())
536 h[wlist[i].row] = wlist[i].w->height();
537 }
538 }
539
540 unsigned w = (desktop->getScreenGeometry().width()
541 * unsigned(taskBarWidthPercentage)) / 100U;
542
543 if (taskBarAtTop) { // !!! for now
544 y[1] = 0;
545 y[0] = h[1] + y[1];
546 #if 0
547 y[0] = 0;
548 if (fIsHidden)
549 y[0]++;
550 y[1] = h[0] + y[0];
551 #endif
552 } else {
553 y[1] = 1;
554 y[0] = h[1] + y[1];
555 }
556
557 right[0] = w;
558 right[1] = w;
559 if (taskBarShowWindows && fTasks != nullptr) {
560 h[0] = max(h[0], max(YIcon::smallSize() + 8, fTasks->maxHeight()));
561 }
562
563 for (int i = 0; i < wcount; i++) {
564 if (!wlist[i].w)
565 continue;
566 if (!wlist[i].show && !wlist[i].w->visible())
567 continue;
568
569 int xx = 0;
570 int yy = 0;
571 int ww = wlist[i].w->width();
572 int hh = h[wlist[i].row];
573
574 if (wlist[i].expand) {
575 yy = y[wlist[i].row];
576 } else {
577 hh = wlist[i].w->height();
578 yy = y[wlist[i].row] + (h[wlist[i].row] - wlist[i].w->height()) / 2;
579 }
580
581 if (wlist[i].left) {
582 xx = left[wlist[i].row] + wlist[i].pre;
583
584 left[wlist[i].row] += ww + wlist[i].pre + wlist[i].post;
585 } else {
586 xx = right[wlist[i].row] - ww - wlist[i].pre;
587
588 right[wlist[i].row] -= ww + wlist[i].pre + wlist[i].post;
589 }
590 YRect r(xx, yy, ww, hh);
591 if (rightToLeft) {
592 r.xx = w - r.xx - r.ww;
593 }
594 wlist[i].w->setGeometry(r);
595 if (wlist[i].show)
596 wlist[i].w->show();
597 }
598
599 wlist.clear();
600 /* ----------------------------------------------------------------- */
601
602 if (taskBarShowWindows && fTasks) {
603 fTasks->hide();
604 YRect r(left[0], y[0], unsigned(max(1, right[0] - left[0])), h[0]);
605 if (rightToLeft) {
606 r.xx = w - r.xx - r.ww;
607 }
608 fTasks->setGeometry(r);
609 fTasks->show();
610 fTasks->relayout();
611 }
612 if (fAddressBar) {
613 int row = taskBarDoubleHeight;
614 YRect r(left[row], y[row] + 2,
615 max(1U, unsigned(right[row] - left[row])), h[row] - 4);
616 if (rightToLeft) {
617 r.xx = w - r.xx - r.ww;
618 }
619 fAddressBar->setGeometry(r);
620 if (::showAddressBar) {
621 if (taskBarDoubleHeight || !taskBarShowWindows) {
622 fAddressBar->raise();
623 fAddressBar->show();
624 }
625 }
626 }
627
628 size_w = w;
629 size_h = h[0] + h[1] + 1;
630 }
631
relayoutNow()632 void TaskBar::relayoutNow() {
633 if (fUpdates.nonempty()) {
634 for (int i = fUpdates.getCount(); --i >= 0; ) {
635 if (i < fUpdates.getCount() && fUpdates[i]) {
636 fUpdates[i]->updateAppStatus();
637 }
638 }
639 fUpdates.clear();
640 }
641 if (windowTrayPane())
642 windowTrayPane()->relayoutNow();
643 if (fNeedRelayout) {
644 updateLocation();
645 }
646 if (taskPane())
647 taskPane()->relayoutNow();
648 if (fButtonUpdate) {
649 fButtonUpdate = false;
650 buttonUpdate();
651 }
652 if (fWorkspacesUpdate) {
653 fWorkspacesUpdate = false;
654 fWorkspaces->repaint();
655 }
656 }
657
updateFullscreen(bool fullscreen)658 void TaskBar::updateFullscreen(bool fullscreen) {
659 if (fFullscreen != fullscreen && getFrame()) {
660 fFullscreen = fullscreen;
661 fEdgeTrigger->show((fFullscreen | fIsHidden) && !fIsCollapsed);
662 }
663 }
664
updateLocation()665 void TaskBar::updateLocation() {
666 fNeedRelayout = false;
667
668 if (getFrame() == nullptr) {
669 showBar();
670 }
671 if (fIsHidden && !fIsCollapsed) {
672 if (getFrame() && visible())
673 getFrame()->wmHide();
674 xapp->sync();
675 }
676
677 int dx, dy;
678 unsigned dw, dh;
679 desktop->getScreenGeometry(&dx, &dy, &dw, &dh, -1);
680
681 int x = dx;
682 unsigned int w = 0;
683 unsigned int h = 0;
684
685 if (taskBarWidthPercentage < 100) {
686 w = (dw * taskBarWidthPercentage + 50) / 100;
687 if (nonempty(taskBarJustify)) {
688 if (strcmp(taskBarJustify, "left") == 0)
689 x = dx;
690 else if (strcmp(taskBarJustify, "right") == 0)
691 x = dx + (dw - w);
692 else if (strcmp(taskBarJustify, "center") == 0)
693 x = dx + (dw - w)/2;
694 }
695 }
696
697 updateLayout(w, h);
698
699 if (fIsCollapsed) {
700 if (fCollapseButton) {
701 w = fCollapseButton->width();
702 h = fCollapseButton->height() + 1;
703 fCollapseButton->setPosition(0, 1);
704 fCollapseButton->raise();
705 fCollapseButton->show();
706 }
707 else {
708 w = h = 0;
709 }
710
711 x = rightToLeft ? dx : dx + (dw - w);
712 }
713
714 int by = taskBarAtTop ? dy : dy + dh - 1;
715
716 fEdgeTrigger->setGeometry(YRect(x, by, w, 1U));
717
718 int y = taskBarAtTop ? dy : dy + dh - h;
719
720 if ( !fIsHidden || fIsCollapsed) {
721 if (getFrame()) {
722 if (geometry() != YRect(x, y, w, h)) {
723 XConfigureRequestEvent conf = {};
724 conf.type = ConfigureRequest;
725 conf.window = handle();
726 conf.x = x;
727 conf.y = y;
728 conf.width = int(w);
729 conf.height = int(h);
730 conf.value_mask = CWX | CWY | CWWidth | CWHeight;
731 getFrame()->configureClient(conf);
732 }
733 getFrame()->wmShow();
734 } else
735 setGeometry(YRect(x, y, w, h));
736 }
737 fEdgeTrigger->show((fFullscreen | fIsHidden) && !fIsCollapsed);
738
739 ///!!! fix
740 updateWMHints();
741 }
742
updateWMHints()743 void TaskBar::updateWMHints() {
744 YStrut strut;
745 if (!taskBarAutoHide && !fIsCollapsed) {
746 YRect geo = desktop->getScreenGeometry();
747 if (y() + height() == geo.y() + geo.height()) {
748 strut.bottom = Atom(height());
749 }
750 else if (y() == geo.y()) {
751 strut.top = Atom(height());
752 }
753 }
754 if (fStrut != strut) {
755 fStrut = strut;
756 MSG(("SET NET WM STRUT"));
757 setProperty(_XA_NET_WM_STRUT, XA_CARDINAL, &strut, 4);
758 }
759 }
760
updateWinLayer()761 void TaskBar::updateWinLayer() {
762 long layer = (taskBarAutoHide || fFullscreen) ? WinLayerAboveAll
763 : fIsCollapsed ? WinLayerAboveDock
764 : taskBarKeepBelow ? WinLayerBelow : WinLayerDock;
765 if (getFrame()) {
766 getFrame()->wmSetLayer(layer);
767 } else {
768 setLayerHint(layer);
769 }
770 }
771
handleFocus(const XFocusChangeEvent & focus)772 void TaskBar::handleFocus(const XFocusChangeEvent& focus) {
773 if (focus.type == FocusOut) {
774 if (focus.mode == NotifyUngrab) {
775 if (focus.detail == NotifyPointer) {
776 updateWMHints();
777 }
778 }
779 }
780 }
781
handleCrossing(const XCrossingEvent & crossing)782 void TaskBar::handleCrossing(const XCrossingEvent &crossing) {
783 unsigned long last = YWindow::getLastEnterNotifySerial();
784 bool ahwm_hack = (crossing.serial != last &&
785 (crossing.serial != last + 1 || crossing.detail != NotifyVirtual));
786
787 if (crossing.type == EnterNotify) {
788 fEdgeTrigger->stopTimer();
789 }
790 else if (crossing.type == LeaveNotify) {
791 if (crossing.detail == NotifyInferior ||
792 (crossing.detail == NotifyVirtual && crossing.mode == NotifyGrab) ||
793 (crossing.detail == NotifyAncestor && crossing.mode != NotifyNormal))
794 {
795 if (ahwm_hack) {
796 fEdgeTrigger->stopTimer();
797 }
798 } else {
799 if (ahwm_hack) {
800 fEdgeTrigger->startTimer();
801 }
802 }
803 }
804 }
805
paint(Graphics & g,const YRect & r)806 void TaskBar::paint(Graphics &g, const YRect& r) {
807 if (taskbackPixbuf != null &&
808 (fGradient == null ||
809 fGradient->width() != width() ||
810 fGradient->height() != height()))
811 {
812 if (taskBarDoubleHeight == false) {
813 fGradient = taskbackPixbuf->scale(width(), height());
814 } else {
815 ref<YImage> s = taskbackPixbuf->scale(width(), (height() + 1) / 2);
816 ref<YPixmap> p = YPixmap::create(width(), height(), depth());
817 Graphics g(p);
818 g.clear();
819 g.copyImage(s, 0, 0);
820 g.copyImage(s, 0, height() - s->height());
821 fGradient = YImage::createFromPixmap(p);
822 }
823 }
824
825 g.setColor(taskBarBg);
826 //g.draw3DRect(0, 0, width() - 1, height() - 1, true);
827
828 // When TaskBarDoubleHeight=1 this draws the upper half.
829 if (fGradient != null) {
830 g.drawImage(fGradient, r.x(), r.y(), r.width(), r.height(),
831 r.x(), r.y());
832 }
833 else if (taskbackPixmap != null) {
834 g.fillPixmap(taskbackPixmap, r.x(), r.y(), r.width(), r.height(),
835 r.x(), r.y());
836 }
837 else if (taskBarAtTop) {
838 bool dh = (r.y() + r.height() == height());
839 g.fillRect(r.x(), r.y(), r.width(), r.height() - dh);
840 if (dh) {
841 g.setColor(taskBarBg->darker());
842 g.drawLine(r.x(), height() - 1, r.x() + r.width(), height() - 1);
843 }
844 }
845 else {
846 bool dy = (r.y() == 0);
847 g.fillRect(r.x(), r.y() + dy, r.width(), r.height() - dy);
848 if (dy) {
849 g.setColor(taskBarBg->brighter());
850 g.drawLine(r.x(), 0, r.x() + r.width(), 0);
851 }
852 }
853 }
854
handleKey(const XKeyEvent & key)855 bool TaskBar::handleKey(const XKeyEvent &key) {
856 return YWindow::handleKey(key);
857 }
858
handleButton(const XButtonEvent & button)859 void TaskBar::handleButton(const XButtonEvent &button) {
860 if ((button.type == ButtonRelease) &&
861 (button.button == 1 || button.button == 3) &&
862 xapp->isButton(button.state, Button1Mask + Button3Mask))
863 {
864 windowList->showFocused(button.x_root, button.y_root);
865 }
866 else {
867 if (button.type == ButtonPress) {
868 manager->updateWorkArea();
869 if (button.button == 1) {
870 if (button.state & xapp->AltMask)
871 lower();
872 else if (!(button.state & ControlMask))
873 raise();
874 }
875 }
876 }
877 YWindow::handleButton(button);
878 }
879
contextMenu(int x_root,int y_root)880 void TaskBar::contextMenu(int x_root, int y_root) {
881 taskBarMenu->popup(this, nullptr, nullptr, x_root, y_root,
882 YPopupWindow::pfCanFlipVertical |
883 YPopupWindow::pfCanFlipHorizontal);
884 }
885
handleClick(const XButtonEvent & up,int count)886 void TaskBar::handleClick(const XButtonEvent &up, int count) {
887 if (up.button == 1) {
888 } else if (up.button == 2) {
889 windowList->showFocused(up.x_root, up.y_root);
890 } else {
891 if (up.button == 3 && count == 1 && xapp->isButton(up.state, Button3Mask)) {
892 contextMenu(up.x_root, up.y_root);
893 }
894 }
895 }
896
handleEndDrag(const XButtonEvent &,const XButtonEvent &)897 void TaskBar::handleEndDrag(const XButtonEvent &/*down*/, const XButtonEvent &/*up*/) {
898 xapp->releaseEvents();
899 }
handleDrag(const XButtonEvent &,const XMotionEvent & motion)900 void TaskBar::handleDrag(const XButtonEvent &/*down*/, const XMotionEvent &motion) {
901 bool newPosition = false;
902
903 xapp->grabEvents(this, YWMApp::movePointer,
904 ButtonPressMask |
905 ButtonReleaseMask |
906 PointerMotionMask);
907
908
909 if (motion.y_root < int(desktop->height() / 2))
910 newPosition = true;
911
912 if (taskBarAtTop != newPosition) {
913 taskBarAtTop = newPosition;
914 updateLocation();
915 }
916 }
917
popupStartMenu()918 void TaskBar::popupStartMenu() {
919 if (fApplications) {
920 popOut();
921 fApplications->popupMenu();
922 }
923 }
924
popupWindowListMenu()925 void TaskBar::popupWindowListMenu() {
926 if (fWinList) {
927 popOut();
928 fWinList->popupMenu();
929 }
930 }
931
autoTimer(bool doShow)932 bool TaskBar::autoTimer(bool doShow) {
933 MSG(("hide taskbar"));
934 if (fFullscreen && doShow && taskBarFullscreenAutoShow) {
935 fIsHidden = false;
936 getFrame()->focus();
937 manager->switchFocusTo(getFrame(), true);
938 manager->updateFullscreenLayer();
939 }
940 if (taskBarAutoHide) {
941 fIsHidden = !doShow && !hasPopup();
942 if (taskBarDoubleHeight == false && taskBarShowWindows) {
943 fIsHidden &= !(addressBar() && addressBar()->visible());
944 }
945 updateLocation();
946 }
947 return fIsHidden == doShow;
948 }
949
popOut()950 void TaskBar::popOut() {
951 if (fIsCollapsed) {
952 handleCollapseButton();
953 }
954 if (taskBarAutoHide) {
955 fIsHidden = false;
956 updateLocation();
957 fIsHidden = taskBarAutoHide;
958 if (fEdgeTrigger) {
959 MSG(("start hide 4"));
960 fEdgeTrigger->startTimer();
961 }
962 }
963 relayoutNow();
964 }
965
showBar()966 void TaskBar::showBar() {
967 if (getFrame() == nullptr) {
968 manager->manageClient(this);
969 updateWinLayer();
970 if (getFrame()) {
971 getFrame()->setAllWorkspaces();
972 if (enableAddressBar && ::showAddressBar && taskBarDoubleHeight)
973 getFrame()->activate(true);
974 parent()->setTitle("TaskBarFrame");
975 getFrame()->updateLayer();
976 }
977 }
978 }
979
actionPerformed(YAction action,unsigned int modifiers)980 void TaskBar::actionPerformed(YAction action, unsigned int modifiers) {
981 wmActionListener->actionPerformed(action, modifiers);
982 }
983
handleCollapseButton()984 void TaskBar::handleCollapseButton() {
985 fIsCollapsed = !fIsCollapsed;
986 if (fCollapseButton) {
987 ref<YImage> image = (leftToRight == fIsCollapsed)
988 ? taskbarExpandImage : taskbarCollapseImage;
989 const char* text = (leftToRight == fIsCollapsed) ? "<" : ">";
990 const char* ttip = fIsCollapsed ? _("Show Taskbar") : _("Hide Taskbar");
991 if (image != null) {
992 fCollapseButton->setImage(image);
993 } else {
994 fCollapseButton->setText(text);
995 }
996 fCollapseButton->setToolTip(ttip);
997 fCollapseButton->repaint();
998 }
999
1000 if (fIsCollapsed)
1001 updateWinLayer();
1002 relayout();
1003 updateLocation();
1004 if (fIsCollapsed == false)
1005 updateWinLayer();
1006 xapp->sync();
1007 }
1008
handlePopDown(YPopupWindow *)1009 void TaskBar::handlePopDown(YPopupWindow * /*popup*/) {
1010 }
1011
configure(const YRect2 & r)1012 void TaskBar::configure(const YRect2& r) {
1013 if (r.resized() && 1 < r.width() && !fIsCollapsed) {
1014 repaint();
1015 clearWindow();
1016 }
1017 updateWMHints();
1018 }
1019
repaint()1020 void TaskBar::repaint() {
1021 GraphicsBuffer(this).paint();
1022 }
1023
detachDesktopTray()1024 void TaskBar::detachDesktopTray() {
1025 if (fDesktopTray) {
1026 MSG(("detach Tray"));
1027 fDesktopTray->detachTray();
1028 delete fDesktopTray; fDesktopTray = nullptr;
1029 }
1030 }
1031
updateFrame(YFrameWindow * frame)1032 void TaskBar::updateFrame(YFrameWindow* frame) {
1033 if (find(fUpdates, frame) < 0)
1034 fUpdates += frame;
1035 }
1036
delistFrame(YFrameWindow * frame,TaskBarApp * task,TrayApp * tray)1037 void TaskBar::delistFrame(YFrameWindow* frame, TaskBarApp* task, TrayApp* tray) {
1038 findRemove(fUpdates, frame);
1039 if (taskPane() && task)
1040 taskPane()->remove(task);
1041 if (windowTrayPane() && tray)
1042 windowTrayPane()->remove(tray);
1043 }
1044
addTasksApp(YFrameWindow * frame)1045 TaskBarApp *TaskBar::addTasksApp(YFrameWindow* frame) {
1046 return taskPane() ? taskPane()->addApp(frame) : nullptr;
1047 }
1048
relayoutTasks()1049 void TaskBar::relayoutTasks() {
1050 if (taskPane())
1051 taskPane()->relayout();
1052 }
1053
addTrayApp(YFrameWindow * frame)1054 TrayApp *TaskBar::addTrayApp(YFrameWindow* frame) {
1055 return windowTrayPane() ? windowTrayPane()->addApp(frame) : nullptr;
1056 }
1057
relayoutTray()1058 void TaskBar::relayoutTray() {
1059 if (windowTrayPane())
1060 windowTrayPane()->relayout();
1061 }
1062
showAddressBar()1063 void TaskBar::showAddressBar() {
1064 popOut();
1065 if (fAddressBar != nullptr)
1066 fAddressBar->showNow();
1067 }
1068
setWorkspaceActive(long workspace,bool active)1069 void TaskBar::setWorkspaceActive(long workspace, bool active) {
1070 if (taskBarShowWorkspaces && fWorkspaces) {
1071 YDimension dim(fWorkspaces->dimension());
1072 fWorkspaces->setPressed(workspace, active);
1073 if (dim != fWorkspaces->dimension()) {
1074 relayout();
1075 }
1076 }
1077 }
1078
workspacesRepaint()1079 void TaskBar::workspacesRepaint() {
1080 if (taskBarShowWorkspaces && fWorkspaces) {
1081 fWorkspacesUpdate = true;
1082 }
1083 }
1084
workspacesUpdateButtons()1085 void TaskBar::workspacesUpdateButtons() {
1086 fButtonUpdate = true;
1087 }
1088
buttonUpdate()1089 void TaskBar::buttonUpdate() {
1090 if (taskBarShowWorkspaces && fWorkspaces) {
1091 YDimension dim(fWorkspaces->dimension());
1092 fWorkspaces->updateButtons();
1093 if (dim != fWorkspaces->dimension()) {
1094 relayout();
1095 }
1096 }
1097 }
1098
workspacesRelabelButtons()1099 void TaskBar::workspacesRelabelButtons() {
1100 if (taskBarShowWorkspaces && fWorkspaces) {
1101 YDimension dim(fWorkspaces->dimension());
1102 fWorkspaces->relabelButtons();
1103 if (dim != fWorkspaces->dimension()) {
1104 relayout();
1105 }
1106 }
1107 }
1108
keyboardUpdate(mstring keyboard)1109 void TaskBar::keyboardUpdate(mstring keyboard) {
1110 if (fKeyboardStatus) {
1111 fKeyboardStatus->updateKeyboard(keyboard);
1112 }
1113 }
1114
windowTrayRequestDock(Window w)1115 bool TaskBar::windowTrayRequestDock(Window w) {
1116 if (fDesktopTray) {
1117 fDesktopTray->trayRequestDock(w, "SystemTray");
1118 return true;
1119 }
1120 return false;
1121 }
1122
switchToPrev()1123 void TaskBar::switchToPrev() {
1124 if (taskPane())
1125 taskPane()->switchToPrev();
1126 }
1127
switchToNext()1128 void TaskBar::switchToNext() {
1129 if (taskPane())
1130 taskPane()->switchToNext();
1131 }
1132
movePrev()1133 void TaskBar::movePrev() {
1134 if (taskPane())
1135 taskPane()->movePrev();
1136 }
1137
moveNext()1138 void TaskBar::moveNext() {
1139 if (taskPane())
1140 taskPane()->moveNext();
1141 }
1142
refresh()1143 void TaskBar::refresh() {
1144 if (fApplications)
1145 fApplications->repaint();
1146 if (fWinList)
1147 fWinList->repaint();
1148 if (fShowDesktop)
1149 fShowDesktop->repaint();
1150 if (fObjectBar)
1151 fObjectBar->refresh();
1152 }
1153
1154 // vim: set sw=4 ts=4 et:
1155