1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Screen.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
24 #include "../config.h"
27 #include <X11/Xatom.h>
28 #include <X11/keysym.h>
37 #endif // HAVE_STDLIB_H
41 #endif // HAVE_STRING_H
45 #endif // HAVE_CTYPE_H
48 # include <sys/types.h>
50 #endif // HAVE_UNISTD_H
54 #endif // HAVE_DIRENT_H
58 #endif // HAVE_LOCALE_H
60 #ifdef HAVE_SYS_STAT_H
61 # include <sys/stat.h>
62 #endif // HAVE_SYS_STAT_H
66 #endif // HAVE_STDARG_H
77 #include "blackbox.hh"
78 #include "Clientmenu.hh"
80 #include "Iconmenu.hh"
84 #include "Rootmenu.hh"
88 #include "Workspace.hh"
89 #include "Workspacemenu.hh"
93 #ifndef FONT_ELEMENT_SIZE
94 #define FONT_ELEMENT_SIZE 50
95 #endif // FONT_ELEMENT_SIZE
98 static bool running = True;
100 static int anotherWMRunning(Display *display, XErrorEvent *) {
101 fprintf(stderr, i18n(ScreenSet, ScreenAnotherWMRunning,
102 "BScreen::BScreen: an error occured while querying the X server.\n"
103 " another window manager already running on display %s.\n"),
104 DisplayString(display));
112 BScreen::BScreen(Blackbox *bb, unsigned int scrn) : ScreenInfo(bb, scrn) {
114 screenstr = (string)"session.screen" + itostring(scrn) + '.';
115 config = blackbox->getConfig();
116 xatom = blackbox->getXAtom();
118 event_mask = ColormapChangeMask | EnterWindowMask | PropertyChangeMask |
119 SubstructureRedirectMask | ButtonPressMask | ButtonReleaseMask;
121 XErrorHandler old = XSetErrorHandler((XErrorHandler) anotherWMRunning);
122 XSelectInput(getBaseDisplay()->getXDisplay(), getRootWindow(), event_mask);
123 XSync(getBaseDisplay()->getXDisplay(), False);
124 XSetErrorHandler((XErrorHandler) old);
127 if (! managed) return;
129 fprintf(stderr, i18n(ScreenSet, ScreenManagingScreen,
130 "BScreen::BScreen: managing screen %d "
131 "using visual 0x%lx, depth %d\n"),
132 getScreenNumber(), XVisualIDFromVisual(getVisual()),
137 resource.mstyle.t_fontset = resource.mstyle.f_fontset =
138 resource.tstyle.fontset = resource.wstyle.fontset = (XFontSet) 0;
139 resource.mstyle.t_font = resource.mstyle.f_font = resource.tstyle.font =
140 resource.wstyle.font = (XFontStruct *) 0;
142 xatom->setSupported(this); // set-up netwm support
144 xatom->setValue(getRootWindow(), XAtom::blackbox_pid, XAtom::cardinal,
145 (unsigned long) getpid());
146 #endif // HAVE_GETPID
147 unsigned long geometry[] = { getWidth(),
149 xatom->setValue(getRootWindow(), XAtom::net_desktop_geometry,
150 XAtom::cardinal, geometry, 2);
151 unsigned long viewport[] = {0,0};
152 xatom->setValue(getRootWindow(), XAtom::net_desktop_viewport,
153 XAtom::cardinal, viewport, 2);
156 XDefineCursor(blackbox->getXDisplay(), getRootWindow(),
157 blackbox->getSessionCursor());
159 // start off full screen, top left.
160 usableArea.setSize(getWidth(), getHeight());
163 new BImageControl(blackbox, this, True, blackbox->getColorsPerChannel(),
164 blackbox->getCacheLife(), blackbox->getCacheMax());
165 image_control->installRootColormap();
166 root_colormap_installed = True;
172 unsigned long gc_value_mask = GCForeground;
173 if (! i18n.multibyte()) gc_value_mask |= GCFont;
175 gcv.foreground = WhitePixel(blackbox->getXDisplay(), getScreenNumber())
176 ^ BlackPixel(blackbox->getXDisplay(), getScreenNumber());
177 gcv.function = GXxor;
178 gcv.subwindow_mode = IncludeInferiors;
179 opGC = XCreateGC(blackbox->getXDisplay(), getRootWindow(),
180 GCForeground | GCFunction | GCSubwindowMode, &gcv);
182 const char *s = i18n(ScreenSet, ScreenPositionLength,
183 "0: 0000 x 0: 0000");
186 if (i18n.multibyte()) {
187 XRectangle ink, logical;
188 XmbTextExtents(resource.wstyle.fontset, s, l, &ink, &logical);
189 geom_w = logical.width;
191 geom_h = resource.wstyle.fontset_extents->max_ink_extent.height;
193 geom_h = resource.wstyle.font->ascent +
194 resource.wstyle.font->descent;
196 geom_w = XTextWidth(resource.wstyle.font, s, l);
199 geom_w += (resource.bevel_width * 2);
200 geom_h += (resource.bevel_width * 2);
202 XSetWindowAttributes attrib;
203 unsigned long mask = CWBorderPixel | CWColormap | CWSaveUnder;
204 attrib.border_pixel = getBorderColor()->pixel();
205 attrib.colormap = getColormap();
206 attrib.save_under = True;
208 geom_window = XCreateWindow(blackbox->getXDisplay(), getRootWindow(),
209 0, 0, geom_w, geom_h, resource.border_width,
210 getDepth(), InputOutput, getVisual(),
212 geom_visible = False;
214 BTexture* texture = &(resource.wstyle.l_focus);
215 geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
216 if (geom_pixmap == ParentRelative) {
217 texture = &(resource.wstyle.t_focus);
218 geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
221 XSetWindowBackground(blackbox->getXDisplay(), geom_window,
222 texture->color().pixel());
224 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
225 geom_window, geom_pixmap);
227 workspacemenu = new Workspacemenu(this);
228 iconmenu = new Iconmenu(this);
229 configmenu = new Configmenu(this);
231 Workspace *wkspc = (Workspace *) 0;
232 if (resource.workspaces != 0) {
233 for (unsigned int i = 0; i < resource.workspaces; ++i) {
234 wkspc = new Workspace(this, workspacesList.size());
235 workspacesList.push_back(wkspc);
236 workspacemenu->insert(wkspc->getName(), wkspc->getMenu());
239 wkspc = new Workspace(this, workspacesList.size());
240 workspacesList.push_back(wkspc);
241 workspacemenu->insert(wkspc->getName(), wkspc->getMenu());
243 saveWorkspaceNames();
245 updateNetizenWorkspaceCount();
247 workspacemenu->insert(i18n(IconSet, IconIcons, "Icons"), iconmenu);
248 workspacemenu->update();
250 current_workspace = workspacesList.front();
252 xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
253 XAtom::cardinal, 0); //first workspace
255 workspacemenu->setItemSelected(2, True);
257 toolbar = new Toolbar(this);
259 slit = new Slit(this);
263 raiseWindows(0, 0); // this also initializes the empty stacking list
266 updateClientList(); // initialize the client list, which will be empty
267 updateAvailableArea();
269 changeWorkspaceID(0);
271 unsigned int i, j, nchild;
272 Window r, p, *children;
273 XQueryTree(blackbox->getXDisplay(), getRootWindow(), &r, &p,
276 // preen the window list of all icon windows... for better dockapp support
277 for (i = 0; i < nchild; i++) {
278 if (children[i] == None) continue;
280 XWMHints *wmhints = XGetWMHints(blackbox->getXDisplay(),
284 if ((wmhints->flags & IconWindowHint) &&
285 (wmhints->icon_window != children[i])) {
286 for (j = 0; j < nchild; j++) {
287 if (children[j] == wmhints->icon_window) {
298 // manage shown windows
299 for (i = 0; i < nchild; ++i) {
300 if (children[i] == None || (! blackbox->validateWindow(children[i])))
303 XWindowAttributes attrib;
304 if (XGetWindowAttributes(blackbox->getXDisplay(), children[i], &attrib)) {
305 if (attrib.override_redirect) continue;
307 if (attrib.map_state != IsUnmapped) {
308 manageWindow(children[i]);
315 // call this again just in case a window we found updates the Strut list
316 updateAvailableArea();
321 BScreen::~BScreen(void) {
322 if (! managed) return;
324 if (geom_pixmap != None)
325 image_control->removeImage(geom_pixmap);
327 if (geom_window != None)
328 XDestroyWindow(blackbox->getXDisplay(), geom_window);
330 std::for_each(workspacesList.begin(), workspacesList.end(),
333 std::for_each(iconList.begin(), iconList.end(), PointerAssassin());
335 std::for_each(netizenList.begin(), netizenList.end(), PointerAssassin());
338 delete workspacemenu;
343 delete image_control;
345 if (resource.wstyle.fontset)
346 XFreeFontSet(blackbox->getXDisplay(), resource.wstyle.fontset);
347 if (resource.mstyle.t_fontset)
348 XFreeFontSet(blackbox->getXDisplay(), resource.mstyle.t_fontset);
349 if (resource.mstyle.f_fontset)
350 XFreeFontSet(blackbox->getXDisplay(), resource.mstyle.f_fontset);
351 if (resource.tstyle.fontset)
352 XFreeFontSet(blackbox->getXDisplay(), resource.tstyle.fontset);
354 if (resource.wstyle.font)
355 XFreeFont(blackbox->getXDisplay(), resource.wstyle.font);
356 if (resource.mstyle.t_font)
357 XFreeFont(blackbox->getXDisplay(), resource.mstyle.t_font);
358 if (resource.mstyle.f_font)
359 XFreeFont(blackbox->getXDisplay(), resource.mstyle.f_font);
360 if (resource.tstyle.font)
361 XFreeFont(blackbox->getXDisplay(), resource.tstyle.font);
363 XFreeGC(blackbox->getXDisplay(), opGC);
367 void BScreen::saveSloppyFocus(bool s) {
368 resource.sloppy_focus = s;
371 if (resource.sloppy_focus) {
372 fmodel = "SloppyFocus";
373 if (resource.auto_raise) fmodel += " AutoRaise";
374 if (resource.click_raise) fmodel += " ClickRaise";
376 fmodel = "ClickToFocus";
378 config->setValue(screenstr + "focusModel", fmodel);
382 void BScreen::saveAutoRaise(bool a) {
383 resource.auto_raise = a;
384 saveSloppyFocus(resource.sloppy_focus);
388 void BScreen::saveClickRaise(bool c) {
389 resource.click_raise = c;
390 saveSloppyFocus(resource.sloppy_focus);
394 void BScreen::saveImageDither(bool d) {
395 image_control->setDither(d);
396 config->setValue(screenstr + "imageDither", doImageDither());
400 void BScreen::saveOpaqueMove(bool o) {
401 resource.opaque_move = o;
402 config->setValue(screenstr + "opaqueMove", resource.opaque_move);
406 void BScreen::saveFullMax(bool f) {
407 resource.full_max = f;
408 config->setValue(screenstr + "fullMaximization", resource.full_max);
412 void BScreen::saveFocusNew(bool f) {
413 resource.focus_new = f;
414 config->setValue(screenstr + "focusNewWindows", resource.focus_new);
418 void BScreen::saveFocusLast(bool f) {
419 resource.focus_last = f;
420 config->setValue(screenstr + "focusLastWindow", resource.focus_last);
424 void BScreen::saveHideToolbar(bool h) {
425 resource.hide_toolbar = h;
426 if (resource.hide_toolbar)
427 toolbar->unmapToolbar();
429 toolbar->mapToolbar();
430 config->setValue(screenstr + "hideToolbar", resource.hide_toolbar);
434 void BScreen::saveWindowToWindowSnap(bool s) {
435 resource.window_to_window_snap = s;
436 config->setValue(screenstr + "windowToWindowSnap",
437 resource.window_to_window_snap);
441 void BScreen::saveWindowCornerSnap(bool s) {
442 resource.window_corner_snap = s;
443 config->setValue(screenstr + "windowCornerSnap",
444 resource.window_corner_snap);
448 void BScreen::saveWorkspaces(unsigned int w) {
449 resource.workspaces = w;
450 config->setValue(screenstr + "workspaces", resource.workspaces);
454 void BScreen::savePlacementPolicy(int p) {
455 resource.placement_policy = p;
456 const char *placement;
457 switch (resource.placement_policy) {
458 case CascadePlacement: placement = "CascadePlacement"; break;
459 case ColSmartPlacement: placement = "ColSmartPlacement"; break;
460 case RowSmartPlacement: default: placement = "RowSmartPlacement"; break;
462 config->setValue(screenstr + "windowPlacement", placement);
466 void BScreen::saveEdgeSnapThreshold(int t) {
467 resource.edge_snap_threshold = t;
468 config->setValue(screenstr + "edgeSnapThreshold",
469 resource.edge_snap_threshold);
473 void BScreen::saveRowPlacementDirection(int d) {
474 resource.row_direction = d;
475 config->setValue(screenstr + "rowPlacementDirection",
476 resource.row_direction == LeftRight ?
477 "LeftToRight" : "RightToLeft");
481 void BScreen::saveColPlacementDirection(int d) {
482 resource.col_direction = d;
483 config->setValue(screenstr + "colPlacementDirection",
484 resource.col_direction == TopBottom ?
485 "TopToBottom" : "BottomToTop");
490 void BScreen::saveStrftimeFormat(const std::string& format) {
491 resource.strftime_format = format;
492 config->setValue(screenstr + "strftimeFormat", resource.strftime_format);
495 #else // !HAVE_STRFTIME
497 void BScreen::saveDateFormat(int f) {
498 resource.date_format = f;
499 config->setValue(screenstr + "dateFormat",
500 resource.date_format == B_EuropeanDate ?
501 "European" : "American");
505 void BScreen::saveClock24Hour(Bool c) {
506 resource.clock24hour = c;
507 config->setValue(screenstr + "clockFormat", resource.clock24hour ? 24 : 12);
509 #endif // HAVE_STRFTIME
512 void BScreen::saveWorkspaceNames() {
513 XAtom::StringVect nameList;
514 unsigned long numnames = (unsigned) -1;
518 xatom->getValue(getRootWindow(), XAtom::net_desktop_names, XAtom::utf8,
519 numnames, nameList)) {
520 for (unsigned int i = 0; i < nameList.size(); ++i) {
521 if (i > 0) names += ",";
522 names += nameList[i];
525 config->setValue(screenstr + "workspaceNames", names);
529 void BScreen::save_rc(void) {
530 saveSloppyFocus(resource.sloppy_focus);
531 saveAutoRaise(resource.auto_raise);
532 saveImageDither(doImageDither());
533 saveOpaqueMove(resource.opaque_move);
534 saveFullMax(resource.full_max);
535 saveFocusNew(resource.focus_new);
536 saveFocusLast(resource.focus_last);
537 saveHideToolbar(resource.hide_toolbar);
538 saveWindowToWindowSnap(resource.window_to_window_snap);
539 saveWindowCornerSnap(resource.window_corner_snap);
540 saveWorkspaces(resource.workspaces);
541 savePlacementPolicy(resource.placement_policy);
542 saveEdgeSnapThreshold(resource.edge_snap_threshold);
543 saveRowPlacementDirection(resource.row_direction);
544 saveColPlacementDirection(resource.col_direction);
546 saveStrftimeFormat(resource.strftime_format);
547 #else // !HAVE_STRFTIME
548 saveDateFormat(resource.date_format);
549 savwClock24Hour(resource.clock24hour);
550 #endif // HAVE_STRFTIME
557 void BScreen::load_rc(void) {
561 if (! config->getValue(screenstr + "fullMaximization", resource.full_max))
562 resource.full_max = false;
564 if (! config->getValue(screenstr + "focusNewWindows", resource.focus_new))
565 resource.focus_new = false;
567 if (! config->getValue(screenstr + "focusLastWindow", resource.focus_last))
568 resource.focus_last = false;
570 if (! config->getValue(screenstr + "workspaces", resource.workspaces))
571 resource.workspaces = 1;
573 if (! config->getValue(screenstr + "opaqueMove", resource.opaque_move))
574 resource.opaque_move = false;
576 if (! config->getValue(screenstr + "hideToolbar", resource.hide_toolbar))
577 resource.hide_toolbar = false;
579 if (! config->getValue(screenstr + "windowToWindowSnap",
580 resource.window_to_window_snap))
581 resource.window_to_window_snap = true;
583 if (! config->getValue(screenstr + "windowCornerSnap",
584 resource.window_corner_snap))
585 resource.window_corner_snap = true;
587 if (! config->getValue(screenstr + "imageDither", b))
589 image_control->setDither(b);
591 if (! config->getValue(screenstr + "edgeSnapThreshold",
592 resource.edge_snap_threshold))
593 resource.edge_snap_threshold = 4;
595 if (config->getValue(screenstr + "rowPlacementDirection", s) &&
597 resource.row_direction = RightLeft;
599 resource.row_direction = LeftRight;
601 if (config->getValue(screenstr + "colPlacementDirection", s) &&
603 resource.col_direction = BottomTop;
605 resource.col_direction = TopBottom;
607 XAtom::StringVect workspaceNames;
608 if (config->getValue(screenstr + "workspaceNames", s)) {
609 string::const_iterator it = s.begin(), end = s.end();
611 string::const_iterator tmp = it; // current string.begin()
612 it = std::find(tmp, end, ','); // look for comma between tmp and end
613 workspaceNames.push_back(string(tmp, it)); // s[tmp:it]
619 xatom->setValue(getRootWindow(), XAtom::net_desktop_names, XAtom::utf8,
622 resource.sloppy_focus = true;
623 resource.auto_raise = false;
624 resource.click_raise = false;
625 if (config->getValue(screenstr + "focusModel", s)) {
626 if (s.find("ClickToFocus") != string::npos) {
627 resource.sloppy_focus = false;
630 if (s.find("AutoRaise") != string::npos)
631 resource.auto_raise = true;
632 if (s.find("ClickRaise") != string::npos)
633 resource.click_raise = true;
637 if (config->getValue(screenstr + "windowPlacement", s)) {
638 if (s == "CascadePlacement")
639 resource.placement_policy = CascadePlacement;
640 else if (s == "ColSmartPlacement")
641 resource.placement_policy = ColSmartPlacement;
642 else //if (s == "RowSmartPlacement")
643 resource.placement_policy = RowSmartPlacement;
645 resource.placement_policy = RowSmartPlacement;
648 if (config->getValue(screenstr + "strftimeFormat", s))
649 resource.strftime_format = s;
651 resource.strftime_format = "%I:%M %p";
652 #else // !HAVE_STRFTIME
655 if (config->getValue(screenstr + "dateFormat", s) && s == "European")
656 resource.date_format = B_EuropeanDate;
658 resource.date_format = B_AmericanDate;
660 if (! config->getValue(screenstr + "clockFormat", l))
662 resource.clock24hour = l == 24;
663 #endif // HAVE_STRFTIME
667 void BScreen::reconfigure(void) {
674 unsigned long gc_value_mask = GCForeground;
675 if (! i18n.multibyte()) gc_value_mask |= GCFont;
677 gcv.foreground = WhitePixel(blackbox->getXDisplay(),
679 gcv.function = GXinvert;
680 gcv.subwindow_mode = IncludeInferiors;
681 XChangeGC(blackbox->getXDisplay(), opGC,
682 GCForeground | GCFunction | GCSubwindowMode, &gcv);
684 const char *s = i18n(ScreenSet, ScreenPositionLength,
685 "0: 0000 x 0: 0000");
688 if (i18n.multibyte()) {
689 XRectangle ink, logical;
690 XmbTextExtents(resource.wstyle.fontset, s, l, &ink, &logical);
691 geom_w = logical.width;
693 geom_h = resource.wstyle.fontset_extents->max_ink_extent.height;
695 geom_w = XTextWidth(resource.wstyle.font, s, l);
697 geom_h = resource.wstyle.font->ascent + resource.wstyle.font->descent;
700 geom_w += (resource.bevel_width * 2);
701 geom_h += (resource.bevel_width * 2);
703 BTexture* texture = &(resource.wstyle.l_focus);
704 geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
705 if (geom_pixmap == ParentRelative) {
706 texture = &(resource.wstyle.t_focus);
707 geom_pixmap = texture->render(geom_w, geom_h, geom_pixmap);
710 XSetWindowBackground(blackbox->getXDisplay(), geom_window,
711 texture->color().pixel());
713 XSetWindowBackgroundPixmap(blackbox->getXDisplay(),
714 geom_window, geom_pixmap);
716 XSetWindowBorderWidth(blackbox->getXDisplay(), geom_window,
717 resource.border_width);
718 XSetWindowBorder(blackbox->getXDisplay(), geom_window,
719 resource.border_color.pixel());
721 workspacemenu->reconfigure();
722 iconmenu->reconfigure();
724 typedef std::vector<int> SubList;
725 SubList remember_subs;
727 // save the current open menus
728 Basemenu *menu = rootmenu;
730 while ((submenu = menu->getCurrentSubmenu()) >= 0) {
731 remember_subs.push_back(submenu);
732 menu = menu->find(submenu)->submenu();
738 rootmenu->reconfigure();
740 // reopen the saved menus
742 const SubList::iterator subs_end = remember_subs.end();
743 for (SubList::iterator it = remember_subs.begin(); it != subs_end; ++it) {
744 menu->drawSubmenu(*it);
745 menu = menu->find(*it)->submenu();
750 configmenu->reconfigure();
752 toolbar->reconfigure();
756 std::for_each(workspacesList.begin(), workspacesList.end(),
757 std::mem_fun(&Workspace::reconfigure));
759 BlackboxWindowList::iterator iit = iconList.begin();
760 for (; iit != iconList.end(); ++iit) {
761 BlackboxWindow *bw = *iit;
762 if (bw->validateClient())
766 image_control->timeout();
770 void BScreen::rereadMenu(void) {
774 rootmenu->reconfigure();
778 void BScreen::LoadStyle(void) {
781 const char *sfile = blackbox->getStyleFilename();
783 style.setFile(sfile);
784 if (! style.load()) {
785 style.setFile(DEFAULTSTYLE);
787 style.create(); // hardcoded default values will be used.
793 // load fonts/fontsets
794 if (resource.wstyle.fontset)
795 XFreeFontSet(blackbox->getXDisplay(), resource.wstyle.fontset);
796 if (resource.tstyle.fontset)
797 XFreeFontSet(blackbox->getXDisplay(), resource.tstyle.fontset);
798 if (resource.mstyle.f_fontset)
799 XFreeFontSet(blackbox->getXDisplay(), resource.mstyle.f_fontset);
800 if (resource.mstyle.t_fontset)
801 XFreeFontSet(blackbox->getXDisplay(), resource.mstyle.t_fontset);
802 resource.wstyle.fontset = 0;
803 resource.tstyle.fontset = 0;
804 resource.mstyle.f_fontset = 0;
805 resource.mstyle.t_fontset = 0;
806 if (resource.wstyle.font)
807 XFreeFont(blackbox->getXDisplay(), resource.wstyle.font);
808 if (resource.tstyle.font)
809 XFreeFont(blackbox->getXDisplay(), resource.tstyle.font);
810 if (resource.mstyle.f_font)
811 XFreeFont(blackbox->getXDisplay(), resource.mstyle.f_font);
812 if (resource.mstyle.t_font)
813 XFreeFont(blackbox->getXDisplay(), resource.mstyle.t_font);
814 resource.wstyle.font = 0;
815 resource.tstyle.font = 0;
816 resource.mstyle.f_font = 0;
817 resource.mstyle.t_font = 0;
819 if (i18n.multibyte()) {
820 resource.wstyle.fontset = readDatabaseFontSet("window.font", style);
821 resource.tstyle.fontset = readDatabaseFontSet("toolbar.font", style);
822 resource.mstyle.t_fontset = readDatabaseFontSet("menu.title.font", style);
823 resource.mstyle.f_fontset = readDatabaseFontSet("menu.frame.font", style);
825 resource.mstyle.t_fontset_extents =
826 XExtentsOfFontSet(resource.mstyle.t_fontset);
827 resource.mstyle.f_fontset_extents =
828 XExtentsOfFontSet(resource.mstyle.f_fontset);
829 resource.tstyle.fontset_extents =
830 XExtentsOfFontSet(resource.tstyle.fontset);
831 resource.wstyle.fontset_extents =
832 XExtentsOfFontSet(resource.wstyle.fontset);
834 resource.wstyle.font = readDatabaseFont("window.font", style);
835 resource.tstyle.font = readDatabaseFont("toolbar.font", style);
836 resource.mstyle.t_font = readDatabaseFont("menu.title.font", style);
837 resource.mstyle.f_font = readDatabaseFont("menu.frame.font", style);
840 // load window config
841 resource.wstyle.t_focus =
842 readDatabaseTexture("window.title.focus", "white", style);
843 resource.wstyle.t_unfocus =
844 readDatabaseTexture("window.title.unfocus", "black", style);
845 resource.wstyle.l_focus =
846 readDatabaseTexture("window.label.focus", "white", style);
847 resource.wstyle.l_unfocus =
848 readDatabaseTexture("window.label.unfocus", "black", style);
849 resource.wstyle.h_focus =
850 readDatabaseTexture("window.handle.focus", "white", style);
851 resource.wstyle.h_unfocus =
852 readDatabaseTexture("window.handle.unfocus", "black", style);
853 resource.wstyle.g_focus =
854 readDatabaseTexture("window.grip.focus", "white", style);
855 resource.wstyle.g_unfocus =
856 readDatabaseTexture("window.grip.unfocus", "black", style);
857 resource.wstyle.b_focus =
858 readDatabaseTexture("window.button.focus", "white", style);
859 resource.wstyle.b_unfocus =
860 readDatabaseTexture("window.button.unfocus", "black", style);
861 resource.wstyle.b_pressed =
862 readDatabaseTexture("window.button.pressed", "black", style);
863 resource.wstyle.f_focus =
864 readDatabaseColor("window.frame.focusColor", "white", style);
865 resource.wstyle.f_unfocus =
866 readDatabaseColor("window.frame.unfocusColor", "black", style);
867 resource.wstyle.l_text_focus =
868 readDatabaseColor("window.label.focus.textColor", "black", style);
869 resource.wstyle.l_text_unfocus =
870 readDatabaseColor("window.label.unfocus.textColor", "white", style);
871 resource.wstyle.b_pic_focus =
872 readDatabaseColor("window.button.focus.picColor", "black", style);
873 resource.wstyle.b_pic_unfocus =
874 readDatabaseColor("window.button.unfocus.picColor", "white", style);
876 resource.wstyle.justify = LeftJustify;
877 if (style.getValue("window.justify", s)) {
878 if (s == "right" || s == "Right")
879 resource.wstyle.justify = RightJustify;
880 else if (s == "center" || s == "Center")
881 resource.wstyle.justify = CenterJustify;
884 // load toolbar config
885 resource.tstyle.toolbar =
886 readDatabaseTexture("toolbar", "black", style);
887 resource.tstyle.label =
888 readDatabaseTexture("toolbar.label", "black", style);
889 resource.tstyle.window =
890 readDatabaseTexture("toolbar.windowLabel", "black", style);
891 resource.tstyle.button =
892 readDatabaseTexture("toolbar.button", "white", style);
893 resource.tstyle.pressed =
894 readDatabaseTexture("toolbar.button.pressed", "black", style);
895 resource.tstyle.clock =
896 readDatabaseTexture("toolbar.clock", "black", style);
897 resource.tstyle.l_text =
898 readDatabaseColor("toolbar.label.textColor", "white", style);
899 resource.tstyle.w_text =
900 readDatabaseColor("toolbar.windowLabel.textColor", "white", style);
901 resource.tstyle.c_text =
902 readDatabaseColor("toolbar.clock.textColor", "white", style);
903 resource.tstyle.b_pic =
904 readDatabaseColor("toolbar.button.picColor", "black", style);
906 resource.tstyle.justify = LeftJustify;
907 if (style.getValue("toolbar.justify", s)) {
908 if (s == "right" || s == "Right")
909 resource.tstyle.justify = RightJustify;
910 else if (s == "center" || s == "Center")
911 resource.tstyle.justify = CenterJustify;
915 resource.mstyle.title =
916 readDatabaseTexture("menu.title", "white", style);
917 resource.mstyle.frame =
918 readDatabaseTexture("menu.frame", "black", style);
919 resource.mstyle.hilite =
920 readDatabaseTexture("menu.hilite", "white", style);
921 resource.mstyle.t_text =
922 readDatabaseColor("menu.title.textColor", "black", style);
923 resource.mstyle.f_text =
924 readDatabaseColor("menu.frame.textColor", "white", style);
925 resource.mstyle.d_text =
926 readDatabaseColor("menu.frame.disableColor", "black", style);
927 resource.mstyle.h_text =
928 readDatabaseColor("menu.hilite.textColor", "black", style);
930 resource.mstyle.t_justify = LeftJustify;
931 if (style.getValue("menu.title.justify", s)) {
932 if (s == "right" || s == "Right")
933 resource.mstyle.t_justify = RightJustify;
934 else if (s == "center" || s == "Center")
935 resource.mstyle.t_justify = CenterJustify;
938 resource.mstyle.f_justify = LeftJustify;
939 if (style.getValue("menu.frame.justify", s)) {
940 if (s == "right" || s == "Right")
941 resource.mstyle.f_justify = RightJustify;
942 else if (s == "center" || s == "Center")
943 resource.mstyle.f_justify = CenterJustify;
946 resource.mstyle.bullet = Basemenu::Triangle;
947 if (style.getValue("menu.bullet", s)) {
948 if (s == "empty" || s == "Empty")
949 resource.mstyle.bullet = Basemenu::Empty;
950 else if (s == "square" || s == "Square")
951 resource.mstyle.bullet = Basemenu::Square;
952 else if (s == "diamond" || s == "Diamond")
953 resource.mstyle.bullet = Basemenu::Diamond;
956 resource.mstyle.bullet_pos = Basemenu::Left;
957 if (style.getValue("menu.bullet.position", s)) {
958 if (s == "right" || s == "Right")
959 resource.mstyle.bullet_pos = Basemenu::Right;
962 resource.border_color =
963 readDatabaseColor("borderColor", "black", style);
965 // load bevel, border and handle widths
966 if (! style.getValue("handleWidth", resource.handle_width) ||
967 resource.handle_width > (getWidth() / 2) || resource.handle_width == 0)
968 resource.handle_width = 6;
970 if (! style.getValue("borderWidth", resource.border_width))
971 resource.border_width = 1;
973 if (! style.getValue("bevelWidth", resource.bevel_width) ||
974 resource.bevel_width > (getWidth() / 2) || resource.bevel_width == 0)
975 resource.bevel_width = 3;
977 if (! style.getValue("frameWidth", resource.frame_width) ||
978 resource.frame_width > (getWidth() / 2))
979 resource.frame_width = resource.bevel_width;
981 if (style.getValue("rootCommand", s))
982 bexec(s, displayString());
986 void BScreen::addIcon(BlackboxWindow *w) {
989 w->setWorkspace(BSENTINEL);
990 w->setWindowNumber(iconList.size());
992 iconList.push_back(w);
994 const char* title = w->getIconTitle();
995 iconmenu->insert(title);
1000 void BScreen::removeIcon(BlackboxWindow *w) {
1005 iconmenu->remove(w->getWindowNumber());
1008 BlackboxWindowList::iterator it = iconList.begin(),
1009 end = iconList.end();
1010 for (int i = 0; it != end; ++it)
1011 (*it)->setWindowNumber(i++);
1015 BlackboxWindow *BScreen::getIcon(unsigned int index) {
1016 if (index < iconList.size()) {
1017 BlackboxWindowList::iterator it = iconList.begin();
1018 for (; index > 0; --index, ++it) ; /* increment to index */
1022 return (BlackboxWindow *) 0;
1026 unsigned int BScreen::addWorkspace(void) {
1027 Workspace *wkspc = new Workspace(this, workspacesList.size());
1028 workspacesList.push_back(wkspc);
1029 saveWorkspaces(getWorkspaceCount());
1031 workspacemenu->insert(wkspc->getName(), wkspc->getMenu(),
1032 wkspc->getID() + 2);
1033 workspacemenu->update();
1035 toolbar->reconfigure();
1037 updateNetizenWorkspaceCount();
1039 return workspacesList.size();
1043 unsigned int BScreen::removeLastWorkspace(void) {
1044 if (workspacesList.size() == 1)
1047 Workspace *wkspc = workspacesList.back();
1049 if (current_workspace->getID() == wkspc->getID())
1050 changeWorkspaceID(current_workspace->getID() - 1);
1054 workspacemenu->remove(wkspc->getID() + 2);
1055 workspacemenu->update();
1057 workspacesList.pop_back();
1060 saveWorkspaces(getWorkspaceCount());
1062 toolbar->reconfigure();
1064 updateNetizenWorkspaceCount();
1066 return workspacesList.size();
1070 void BScreen::changeWorkspaceID(unsigned int id) {
1071 if (! current_workspace) return;
1073 if (id != current_workspace->getID()) {
1074 BlackboxWindow *focused = blackbox->getFocusedWindow();
1075 if (focused && focused->getScreen() == this && ! focused->isStuck()) {
1076 if (focused->getWorkspaceNumber() != current_workspace->getID()) {
1077 fprintf(stderr, "%s is on the wrong workspace, aborting\n",
1078 focused->getTitle());
1081 current_workspace->setLastFocusedWindow(focused);
1083 // if no window had focus, no need to store a last focus
1084 current_workspace->setLastFocusedWindow((BlackboxWindow *) 0);
1086 // when we switch workspaces, unfocus whatever was focused
1087 blackbox->setFocusedWindow((BlackboxWindow *) 0);
1089 current_workspace->hideAll();
1090 workspacemenu->setItemSelected(current_workspace->getID() + 2, False);
1092 current_workspace = getWorkspace(id);
1094 xatom->setValue(getRootWindow(), XAtom::net_current_desktop,
1095 XAtom::cardinal, id);
1097 workspacemenu->setItemSelected(current_workspace->getID() + 2, True);
1098 toolbar->redrawWorkspaceLabel(True);
1100 current_workspace->showAll();
1102 if (resource.focus_last && current_workspace->getLastFocusedWindow()) {
1103 XSync(blackbox->getXDisplay(), False);
1104 current_workspace->getLastFocusedWindow()->setInputFocus();
1108 updateNetizenCurrentWorkspace();
1113 * Set the _NET_CLIENT_LIST root window property.
1115 void BScreen::updateClientList(void) {
1116 if (windowList.size() > 0) {
1117 Window *windows = new Window[windowList.size()];
1118 Window *win_it = windows;
1119 BlackboxWindowList::iterator it = windowList.begin();
1120 const BlackboxWindowList::iterator end = windowList.end();
1121 for (; it != end; ++it, ++win_it)
1122 *win_it = (*it)->getClientWindow();
1123 xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1124 windows, windowList.size());
1127 xatom->setValue(getRootWindow(), XAtom::net_client_list, XAtom::window,
1133 * Set the _NET_CLIENT_LIST_STACKING root window property.
1135 void BScreen::updateStackingList(void) {
1137 BlackboxWindowList stack_order;
1140 * Get the atacking order from all of the workspaces.
1141 * We start with the current workspace so that the sticky windows will be
1142 * in the right order on the current workspace.
1143 * XXX: Do we need to have sticky windows in the list once for each workspace?
1145 getCurrentWorkspace()->appendStackOrder(stack_order);
1146 for (unsigned int i = 0; i < getWorkspaceCount(); ++i)
1147 if (i != getCurrentWorkspaceID())
1148 getWorkspace(i)->appendStackOrder(stack_order);
1150 if (stack_order.size() > 0) {
1151 // set the client list atoms
1152 Window *windows = new Window[stack_order.size()];
1153 Window *win_it = windows;
1154 BlackboxWindowList::iterator it = stack_order.begin();
1155 const BlackboxWindowList::iterator end = stack_order.end();
1156 for (; it != end; ++it, ++win_it)
1157 *win_it = (*it)->getClientWindow();
1158 xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1159 XAtom::window, windows, stack_order.size());
1162 xatom->setValue(getRootWindow(), XAtom::net_client_list_stacking,
1163 XAtom::window, 0, 0);
1167 void BScreen::addSystrayWindow(Window window) {
1168 systrayWindowList.push_back(window);
1169 xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1171 &systrayWindowList[0], systrayWindowList.size());
1172 blackbox->saveSystrayWindowSearch(window, this);
1176 void BScreen::removeSystrayWindow(Window window) {
1177 WindowList::iterator it = systrayWindowList.begin();
1178 const WindowList::iterator end = systrayWindowList.end();
1179 for (; it != end; ++it)
1180 if (*it == window) {
1181 systrayWindowList.erase(it);
1182 xatom->setValue(getRootWindow(), XAtom::kde_net_system_tray_windows,
1184 &systrayWindowList[0], systrayWindowList.size());
1185 blackbox->removeSystrayWindowSearch(window);
1191 void BScreen::addDesktopWindow(Window window) {
1192 desktopWindowList.push_back(window);
1193 XLowerWindow(blackbox->getXDisplay(), window);
1194 XSelectInput(blackbox->getXDisplay(), window, StructureNotifyMask);
1195 blackbox->saveDesktopWindowSearch(window, this);
1199 void BScreen::removeDesktopWindow(Window window) {
1200 WindowList::iterator it = desktopWindowList.begin();
1201 const WindowList::iterator end = desktopWindowList.end();
1202 for (; it != end; ++it)
1203 if (*it == window) {
1204 desktopWindowList.erase(it);
1205 XSelectInput(blackbox->getXDisplay(), window, None);
1206 blackbox->removeDesktopWindowSearch(window);
1212 void BScreen::manageWindow(Window w) {
1213 new BlackboxWindow(blackbox, w, this);
1215 BlackboxWindow *win = blackbox->searchWindow(w);
1218 if (win->isDesktop()) {
1219 // desktop windows cant do anything, so we remove all the normal window
1220 // stuff from them, they are only kept around so that we can keep them on
1221 // the bottom of the z-order
1223 addDesktopWindow(win->getClientWindow());
1228 windowList.push_back(win);
1231 XMapRequestEvent mre;
1233 if (blackbox->isStartup()) win->restoreAttributes();
1234 win->mapRequestEvent(&mre);
1238 void BScreen::unmanageWindow(BlackboxWindow *w, bool remap) {
1241 if (w->getWorkspaceNumber() != BSENTINEL &&
1242 w->getWindowNumber() != BSENTINEL)
1243 getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1244 else if (w->isIconic())
1247 windowList.remove(w);
1250 if (blackbox->getFocusedWindow() == w)
1251 blackbox->setFocusedWindow((BlackboxWindow *) 0);
1253 removeNetizen(w->getClientWindow());
1256 some managed windows can also be window group controllers. when
1257 unmanaging such windows, we should also delete the window group.
1259 BWindowGroup *group = blackbox->searchGroup(w->getClientWindow());
1266 void BScreen::addNetizen(Netizen *n) {
1267 netizenList.push_back(n);
1269 n->sendWorkspaceCount();
1270 n->sendCurrentWorkspace();
1272 WorkspaceList::iterator it = workspacesList.begin();
1273 const WorkspaceList::iterator end = workspacesList.end();
1274 for (; it != end; ++it)
1275 (*it)->sendWindowList(*n);
1277 Window f = ((blackbox->getFocusedWindow()) ?
1278 blackbox->getFocusedWindow()->getClientWindow() : None);
1279 n->sendWindowFocus(f);
1283 void BScreen::removeNetizen(Window w) {
1284 NetizenList::iterator it = netizenList.begin();
1285 for (; it != netizenList.end(); ++it) {
1286 if ((*it)->getWindowID() == w) {
1288 netizenList.erase(it);
1295 void BScreen::updateWorkArea(void) {
1296 if (workspacesList.size() > 0) {
1297 unsigned long *dims = new unsigned long[4 * workspacesList.size()];
1298 for (unsigned int i = 0, m = workspacesList.size(); i < m; ++i) {
1299 // XXX: this could be different for each workspace
1300 const Rect &area = availableArea();
1301 dims[(i * 4) + 0] = area.x();
1302 dims[(i * 4) + 1] = area.y();
1303 dims[(i * 4) + 2] = area.width();
1304 dims[(i * 4) + 3] = area.height();
1306 xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1307 dims, 4 * workspacesList.size());
1309 xatom->setValue(getRootWindow(), XAtom::net_workarea, XAtom::cardinal,
1314 void BScreen::updateNetizenCurrentWorkspace(void) {
1315 std::for_each(netizenList.begin(), netizenList.end(),
1316 std::mem_fun(&Netizen::sendCurrentWorkspace));
1320 void BScreen::updateNetizenWorkspaceCount(void) {
1321 xatom->setValue(getRootWindow(), XAtom::net_number_of_desktops,
1322 XAtom::cardinal, workspacesList.size());
1326 std::for_each(netizenList.begin(), netizenList.end(),
1327 std::mem_fun(&Netizen::sendWorkspaceCount));
1331 void BScreen::updateNetizenWindowFocus(void) {
1332 Window f = ((blackbox->getFocusedWindow()) ?
1333 blackbox->getFocusedWindow()->getClientWindow() : None);
1335 xatom->setValue(getRootWindow(), XAtom::net_active_window,
1338 NetizenList::iterator it = netizenList.begin();
1339 for (; it != netizenList.end(); ++it)
1340 (*it)->sendWindowFocus(f);
1344 void BScreen::updateNetizenWindowAdd(Window w, unsigned long p) {
1345 NetizenList::iterator it = netizenList.begin();
1346 for (; it != netizenList.end(); ++it) {
1347 (*it)->sendWindowAdd(w, p);
1352 void BScreen::updateNetizenWindowDel(Window w) {
1353 NetizenList::iterator it = netizenList.begin();
1354 for (; it != netizenList.end(); ++it)
1355 (*it)->sendWindowDel(w);
1359 void BScreen::updateNetizenWindowRaise(Window w) {
1360 NetizenList::iterator it = netizenList.begin();
1361 for (; it != netizenList.end(); ++it)
1362 (*it)->sendWindowRaise(w);
1366 void BScreen::updateNetizenWindowLower(Window w) {
1367 NetizenList::iterator it = netizenList.begin();
1368 for (; it != netizenList.end(); ++it)
1369 (*it)->sendWindowLower(w);
1373 void BScreen::updateNetizenConfigNotify(XEvent *e) {
1374 NetizenList::iterator it = netizenList.begin();
1375 for (; it != netizenList.end(); ++it)
1376 (*it)->sendConfigNotify(e);
1380 void BScreen::raiseWindows(Window *workspace_stack, unsigned int num) {
1381 // the 13 represents the number of blackbox windows such as menus
1382 Window *session_stack = new
1383 Window[(num + workspacesList.size() + rootmenuList.size() + 13)];
1384 unsigned int i = 0, k = num;
1386 XRaiseWindow(blackbox->getXDisplay(), iconmenu->getWindowID());
1387 *(session_stack + i++) = iconmenu->getWindowID();
1389 WorkspaceList::iterator wit = workspacesList.begin();
1390 const WorkspaceList::iterator w_end = workspacesList.end();
1391 for (; wit != w_end; ++wit)
1392 *(session_stack + i++) = (*wit)->getMenu()->getWindowID();
1394 *(session_stack + i++) = workspacemenu->getWindowID();
1396 *(session_stack + i++) = configmenu->getFocusmenu()->getWindowID();
1397 *(session_stack + i++) = configmenu->getPlacementmenu()->getWindowID();
1398 *(session_stack + i++) = configmenu->getWindowID();
1400 *(session_stack + i++) = slit->getMenu()->getDirectionmenu()->getWindowID();
1401 *(session_stack + i++) = slit->getMenu()->getPlacementmenu()->getWindowID();
1402 *(session_stack + i++) = slit->getMenu()->getWindowID();
1404 *(session_stack + i++) =
1405 toolbar->getMenu()->getPlacementmenu()->getWindowID();
1406 *(session_stack + i++) = toolbar->getMenu()->getWindowID();
1408 RootmenuList::iterator rit = rootmenuList.begin();
1409 for (; rit != rootmenuList.end(); ++rit)
1410 *(session_stack + i++) = (*rit)->getWindowID();
1411 *(session_stack + i++) = rootmenu->getWindowID();
1413 if (toolbar->isOnTop())
1414 *(session_stack + i++) = toolbar->getWindowID();
1416 if (slit->isOnTop())
1417 *(session_stack + i++) = slit->getWindowID();
1420 *(session_stack + i++) = *(workspace_stack + k);
1422 XRestackWindows(blackbox->getXDisplay(), session_stack, i);
1424 delete [] session_stack;
1426 updateStackingList();
1430 void BScreen::lowerDesktops(void) {
1431 if (desktopWindowList.empty()) return;
1433 XLowerWindow(blackbox->getXDisplay(), desktopWindowList[0]);
1434 if (desktopWindowList.size() > 1)
1435 XRestackWindows(blackbox->getXDisplay(), &desktopWindowList[0],
1436 desktopWindowList.size());
1440 void BScreen::reassociateWindow(BlackboxWindow *w, unsigned int wkspc_id,
1441 bool ignore_sticky) {
1444 if (wkspc_id == BSENTINEL)
1445 wkspc_id = current_workspace->getID();
1447 if (w->getWorkspaceNumber() == wkspc_id)
1450 if (w->isIconic()) {
1452 getWorkspace(wkspc_id)->addWindow(w);
1453 } else if (ignore_sticky || ! w->isStuck()) {
1454 getWorkspace(w->getWorkspaceNumber())->removeWindow(w);
1455 getWorkspace(wkspc_id)->addWindow(w);
1460 void BScreen::propagateWindowName(const BlackboxWindow *bw) {
1461 if (bw->isIconic()) {
1462 iconmenu->changeItemLabel(bw->getWindowNumber(), bw->getIconTitle());
1466 Clientmenu *clientmenu = getWorkspace(bw->getWorkspaceNumber())->getMenu();
1467 clientmenu->changeItemLabel(bw->getWindowNumber(), bw->getTitle());
1468 clientmenu->update();
1470 if (blackbox->getFocusedWindow() == bw)
1471 toolbar->redrawWindowLabel(True);
1476 void BScreen::nextFocus(void) {
1477 BlackboxWindow *focused = blackbox->getFocusedWindow(),
1481 // if window is not on this screen, ignore it
1482 if (focused->getScreen()->getScreenNumber() != getScreenNumber())
1483 focused = (BlackboxWindow*) 0;
1486 if (focused && current_workspace->getCount() > 1) {
1487 // next is the next window to recieve focus, current is a place holder
1488 BlackboxWindow *current;
1491 next = current_workspace->getNextWindowInList(current);
1492 } while(! next->setInputFocus() && next != focused);
1494 if (next != focused)
1495 current_workspace->raiseWindow(next);
1496 } else if (current_workspace->getCount() >= 1) {
1497 next = current_workspace->getTopWindowOnStack();
1499 current_workspace->raiseWindow(next);
1500 next->setInputFocus();
1505 void BScreen::prevFocus(void) {
1506 BlackboxWindow *focused = blackbox->getFocusedWindow(),
1510 // if window is not on this screen, ignore it
1511 if (focused->getScreen()->getScreenNumber() != getScreenNumber())
1512 focused = (BlackboxWindow*) 0;
1515 if (focused && current_workspace->getCount() > 1) {
1516 // next is the next window to recieve focus, current is a place holder
1517 BlackboxWindow *current;
1520 next = current_workspace->getPrevWindowInList(current);
1521 } while(! next->setInputFocus() && next != focused);
1523 if (next != focused)
1524 current_workspace->raiseWindow(next);
1525 } else if (current_workspace->getCount() >= 1) {
1526 next = current_workspace->getTopWindowOnStack();
1528 current_workspace->raiseWindow(next);
1529 next->setInputFocus();
1534 void BScreen::raiseFocus(void) {
1535 BlackboxWindow *focused = blackbox->getFocusedWindow();
1539 // if on this Screen, raise it
1540 if (focused->getScreen()->getScreenNumber() == getScreenNumber()) {
1541 Workspace *workspace = getWorkspace(focused->getWorkspaceNumber());
1542 workspace->raiseWindow(focused);
1547 void BScreen::InitMenu(void) {
1549 rootmenuList.clear();
1551 while (rootmenu->getCount())
1552 rootmenu->remove(0);
1554 rootmenu = new Rootmenu(this);
1556 bool defaultMenu = True;
1558 FILE *menu_file = (FILE *) 0;
1559 const char *menu_filename = blackbox->getMenuFilename();
1562 if (! (menu_file = fopen(menu_filename, "r")))
1563 perror(menu_filename);
1564 if (! menu_file) { // opening the menu file failed, try the default menu
1565 menu_filename = DEFAULTMENU;
1566 if (! (menu_file = fopen(menu_filename, "r")))
1567 perror(menu_filename);
1571 if (feof(menu_file)) {
1572 fprintf(stderr, i18n(ScreenSet, ScreenEmptyMenuFile,
1573 "%s: Empty menu file"),
1576 char line[1024], label[1024];
1577 memset(line, 0, 1024);
1578 memset(label, 0, 1024);
1580 while (fgets(line, 1024, menu_file) && ! feof(menu_file)) {
1581 if (line[0] != '#') {
1582 int i, key = 0, index = -1, len = strlen(line);
1584 for (i = 0; i < len; i++) {
1585 if (line[i] == '[') index = 0;
1586 else if (line[i] == ']') break;
1587 else if (line[i] != ' ')
1589 key += tolower(line[i]);
1592 if (key == 517) { // [begin]
1594 for (i = index; i < len; i++) {
1595 if (line[i] == '(') index = 0;
1596 else if (line[i] == ')') break;
1597 else if (index++ >= 0) {
1598 if (line[i] == '\\' && i < len - 1) i++;
1599 label[index - 1] = line[i];
1603 if (index == -1) index = 0;
1604 label[index] = '\0';
1606 rootmenu->setLabel(label);
1607 defaultMenu = parseMenuFile(menu_file, rootmenu);
1609 blackbox->addMenuTimestamp(menu_filename);
1619 rootmenu->setInternalMenu();
1620 rootmenu->insert(i18n(ScreenSet, Screenxterm, "xterm"),
1622 i18n(ScreenSet, Screenxterm, "xterm"));
1623 rootmenu->insert(i18n(ScreenSet, ScreenRestart, "Restart"),
1625 rootmenu->insert(i18n(ScreenSet, ScreenExit, "Exit"),
1627 rootmenu->setLabel(i18n(BasemenuSet, BasemenuBlackboxMenu,
1633 bool BScreen::parseMenuFile(FILE *file, Rootmenu *menu) {
1634 char line[1024], label[1024], command[1024];
1636 while (! feof(file)) {
1637 memset(line, 0, 1024);
1638 memset(label, 0, 1024);
1639 memset(command, 0, 1024);
1641 if (fgets(line, 1024, file)) {
1642 if (line[0] != '#') {
1643 int i, key = 0, parse = 0, index = -1, line_length = strlen(line);
1645 // determine the keyword
1646 for (i = 0; i < line_length; i++) {
1647 if (line[i] == '[') parse = 1;
1648 else if (line[i] == ']') break;
1649 else if (line[i] != ' ')
1651 key += tolower(line[i]);
1654 // get the label enclosed in ()'s
1657 for (i = 0; i < line_length; i++) {
1658 if (line[i] == '(') {
1661 } else if (line[i] == ')') break;
1662 else if (index++ >= 0) {
1663 if (line[i] == '\\' && i < line_length - 1) i++;
1664 label[index - 1] = line[i];
1669 label[index] = '\0';
1674 // get the command enclosed in {}'s
1677 for (i = 0; i < line_length; i++) {
1678 if (line[i] == '{') {
1681 } else if (line[i] == '}') break;
1682 else if (index++ >= 0) {
1683 if (line[i] == '\\' && i < line_length - 1) i++;
1684 command[index - 1] = line[i];
1689 command[index] = '\0';
1696 return ((menu->getCount() == 0) ? True : False);
1703 menu->insert(label);
1708 if ((! *label) && (! *command)) {
1709 fprintf(stderr, i18n(ScreenSet, ScreenEXECError,
1710 "BScreen::parseMenuFile: [exec] error, "
1711 "no menu label and/or command defined\n"));
1715 menu->insert(label, BScreen::Execute, command);
1721 fprintf(stderr, i18n(ScreenSet, ScreenEXITError,
1722 "BScreen::parseMenuFile: [exit] error, "
1723 "no menu label defined\n"));
1727 menu->insert(label, BScreen::Exit);
1733 if ((! *label) || (! *command)) {
1735 i18n(ScreenSet, ScreenSTYLEError,
1736 "BScreen::parseMenuFile: [style] error, "
1737 "no menu label and/or filename defined\n"));
1741 string style = expandTilde(command);
1743 menu->insert(label, BScreen::SetStyle, style.c_str());
1750 fprintf(stderr, i18n(ScreenSet, ScreenCONFIGError,
1751 "BScreen::parseMenufile: [config] error, "
1752 "no label defined"));
1756 menu->insert(label, configmenu);
1760 case 740: // include
1763 fprintf(stderr, i18n(ScreenSet, ScreenINCLUDEError,
1764 "BScreen::parseMenuFile: [include] error, "
1765 "no filename defined\n"));
1769 string newfile = expandTilde(label);
1770 FILE *submenufile = fopen(newfile.c_str(), "r");
1774 if (fstat(fileno(submenufile), &buf) ||
1775 (! S_ISREG(buf.st_mode))) {
1777 i18n(ScreenSet, ScreenINCLUDEErrorReg,
1778 "BScreen::parseMenuFile: [include] error: "
1779 "'%s' is not a regular file\n"), newfile.c_str());
1783 if (! feof(submenufile)) {
1784 if (! parseMenuFile(submenufile, menu))
1785 blackbox->addMenuTimestamp(newfile);
1787 fclose(submenufile);
1790 perror(newfile.c_str());
1796 case 767: // submenu
1799 fprintf(stderr, i18n(ScreenSet, ScreenSUBMENUError,
1800 "BScreen::parseMenuFile: [submenu] error, "
1801 "no menu label defined\n"));
1805 Rootmenu *submenu = new Rootmenu(this);
1808 submenu->setLabel(command);
1810 submenu->setLabel(label);
1812 parseMenuFile(file, submenu);
1814 menu->insert(label, submenu);
1815 rootmenuList.push_back(submenu);
1820 case 773: // restart
1823 fprintf(stderr, i18n(ScreenSet, ScreenRESTARTError,
1824 "BScreen::parseMenuFile: [restart] error, "
1825 "no menu label defined\n"));
1830 menu->insert(label, BScreen::RestartOther, command);
1832 menu->insert(label, BScreen::Restart);
1837 case 845: // reconfig
1841 i18n(ScreenSet, ScreenRECONFIGError,
1842 "BScreen::parseMenuFile: [reconfig] error, "
1843 "no menu label defined\n"));
1847 menu->insert(label, BScreen::Reconfigure);
1852 case 995: // stylesdir
1853 case 1113: // stylesmenu
1855 bool newmenu = ((key == 1113) ? True : False);
1857 if ((! *label) || ((! *command) && newmenu)) {
1859 i18n(ScreenSet, ScreenSTYLESDIRError,
1860 "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
1861 " error, no directory defined\n"));
1865 char *directory = ((newmenu) ? command : label);
1867 string stylesdir = expandTilde(directory);
1869 struct stat statbuf;
1871 if (! stat(stylesdir.c_str(), &statbuf)) {
1872 if (S_ISDIR(statbuf.st_mode)) {
1873 Rootmenu *stylesmenu;
1876 stylesmenu = new Rootmenu(this);
1880 DIR *d = opendir(stylesdir.c_str());
1882 std::vector<string> ls;
1884 while((p = readdir(d)))
1885 ls.push_back(p->d_name);
1889 std::sort(ls.begin(), ls.end());
1891 std::vector<string>::iterator it = ls.begin(),
1893 for (; it != end; ++it) {
1894 const string& fname = *it;
1896 if (fname[fname.size()-1] == '~')
1899 string style = stylesdir;
1903 if ((! stat(style.c_str(), &statbuf)) &&
1904 S_ISREG(statbuf.st_mode))
1905 stylesmenu->insert(fname, BScreen::SetStyle, style);
1908 stylesmenu->update();
1911 stylesmenu->setLabel(label);
1912 menu->insert(label, stylesmenu);
1913 rootmenuList.push_back(stylesmenu);
1916 blackbox->addMenuTimestamp(stylesdir);
1919 i18n(ScreenSet, ScreenSTYLESDIRErrorNotDir,
1920 "BScreen::parseMenuFile:"
1921 " [stylesdir/stylesmenu] error, %s is not a"
1922 " directory\n"), stylesdir.c_str());
1926 i18n(ScreenSet, ScreenSTYLESDIRErrorNoExist,
1927 "BScreen::parseMenuFile: [stylesdir/stylesmenu]"
1928 " error, %s does not exist\n"), stylesdir.c_str());
1933 case 1090: // workspaces
1937 i18n(ScreenSet, ScreenWORKSPACESError,
1938 "BScreen:parseMenuFile: [workspaces] error, "
1939 "no menu label defined\n"));
1943 menu->insert(label, workspacemenu);
1952 return ((menu->getCount() == 0) ? True : False);
1956 void BScreen::shutdown(void) {
1957 XSelectInput(blackbox->getXDisplay(), getRootWindow(), NoEventMask);
1958 XSync(blackbox->getXDisplay(), False);
1960 while(! windowList.empty())
1961 unmanageWindow(windowList.front(), True);
1967 void BScreen::showPosition(int x, int y) {
1968 if (! geom_visible) {
1969 XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
1970 (getWidth() - geom_w) / 2,
1971 (getHeight() - geom_h) / 2, geom_w, geom_h);
1972 XMapWindow(blackbox->getXDisplay(), geom_window);
1973 XRaiseWindow(blackbox->getXDisplay(), geom_window);
1975 geom_visible = True;
1980 sprintf(label, i18n(ScreenSet, ScreenPositionFormat,
1981 "X: %4d x Y: %4d"), x, y);
1983 XClearWindow(blackbox->getXDisplay(), geom_window);
1985 BPen pen(resource.wstyle.l_text_focus, resource.wstyle.font);
1986 if (i18n.multibyte()) {
1987 XmbDrawString(blackbox->getXDisplay(), geom_window,
1988 resource.wstyle.fontset, pen.gc(),
1989 resource.bevel_width, resource.bevel_width -
1990 resource.wstyle.fontset_extents->max_ink_extent.y,
1991 label, strlen(label));
1993 XDrawString(blackbox->getXDisplay(), geom_window,
1994 pen.gc(), resource.bevel_width,
1995 resource.wstyle.font->ascent + resource.bevel_width,
1996 label, strlen(label));
2001 void BScreen::showGeometry(unsigned int gx, unsigned int gy) {
2002 if (! geom_visible) {
2003 XMoveResizeWindow(blackbox->getXDisplay(), geom_window,
2004 (getWidth() - geom_w) / 2,
2005 (getHeight() - geom_h) / 2, geom_w, geom_h);
2006 XMapWindow(blackbox->getXDisplay(), geom_window);
2007 XRaiseWindow(blackbox->getXDisplay(), geom_window);
2009 geom_visible = True;
2014 sprintf(label, i18n(ScreenSet, ScreenGeometryFormat,
2015 "W: %4d x H: %4d"), gx, gy);
2017 XClearWindow(blackbox->getXDisplay(), geom_window);
2019 BPen pen(resource.wstyle.l_text_focus, resource.wstyle.font);
2020 if (i18n.multibyte()) {
2021 XmbDrawString(blackbox->getXDisplay(), geom_window,
2022 resource.wstyle.fontset, pen.gc(),
2023 resource.bevel_width, resource.bevel_width -
2024 resource.wstyle.fontset_extents->max_ink_extent.y,
2025 label, strlen(label));
2027 XDrawString(blackbox->getXDisplay(), geom_window,
2028 pen.gc(), resource.bevel_width,
2029 resource.wstyle.font->ascent +
2030 resource.bevel_width, label, strlen(label));
2035 void BScreen::hideGeometry(void) {
2037 XUnmapWindow(blackbox->getXDisplay(), geom_window);
2038 geom_visible = False;
2043 void BScreen::addStrut(Strut *strut) {
2044 strutList.push_back(strut);
2048 void BScreen::removeStrut(Strut *strut) {
2049 strutList.remove(strut);
2053 const Rect& BScreen::availableArea(void) const {
2055 return getRect(); // return the full screen
2060 void BScreen::updateAvailableArea(void) {
2061 Rect old_area = usableArea;
2062 usableArea = getRect(); // reset to full screen
2064 /* these values represent offsets from the screen edge
2065 * we look for the biggest offset on each edge and then apply them
2067 * do not be confused by the similarity to the names of Rect's members
2069 unsigned int current_left = 0, current_right = 0, current_top = 0,
2072 StrutList::const_iterator it = strutList.begin(), end = strutList.end();
2074 for(; it != end; ++it) {
2076 if (strut->left > current_left)
2077 current_left = strut->left;
2078 if (strut->top > current_top)
2079 current_top = strut->top;
2080 if (strut->right > current_right)
2081 current_right = strut->right;
2082 if (strut->bottom > current_bottom)
2083 current_bottom = strut->bottom;
2086 usableArea.setPos(current_left, current_top);
2087 usableArea.setSize(usableArea.width() - (current_left + current_right),
2088 usableArea.height() - (current_top + current_bottom));
2090 if (old_area != usableArea) {
2091 BlackboxWindowList::iterator it = windowList.begin(),
2092 end = windowList.end();
2093 for (; it != end; ++it)
2094 if ((*it)->isMaximized()) (*it)->remaximize();
2101 Workspace* BScreen::getWorkspace(unsigned int index) {
2102 assert(index < workspacesList.size());
2103 return workspacesList[index];
2107 void BScreen::buttonPressEvent(XButtonEvent *xbutton) {
2108 if (xbutton->button == 1) {
2109 if (! isRootColormapInstalled())
2110 image_control->installRootColormap();
2112 if (workspacemenu->isVisible())
2113 workspacemenu->hide();
2115 if (rootmenu->isVisible())
2117 } else if (xbutton->button == 2) {
2118 int mx = xbutton->x_root - (workspacemenu->getWidth() / 2);
2119 int my = xbutton->y_root - (workspacemenu->getTitleHeight() / 2);
2124 if (mx + workspacemenu->getWidth() > getWidth())
2125 mx = getWidth() - workspacemenu->getWidth() - getBorderWidth();
2127 if (my + workspacemenu->getHeight() > getHeight())
2128 my = getHeight() - workspacemenu->getHeight() - getBorderWidth();
2130 workspacemenu->move(mx, my);
2132 if (! workspacemenu->isVisible()) {
2133 workspacemenu->removeParent();
2134 workspacemenu->show();
2136 } else if (xbutton->button == 3) {
2137 int mx = xbutton->x_root - (rootmenu->getWidth() / 2);
2138 int my = xbutton->y_root - (rootmenu->getTitleHeight() / 2);
2143 if (mx + rootmenu->getWidth() > getWidth())
2144 mx = getWidth() - rootmenu->getWidth() - getBorderWidth();
2146 if (my + rootmenu->getHeight() > getHeight())
2147 my = getHeight() - rootmenu->getHeight() - getBorderWidth();
2149 rootmenu->move(mx, my);
2151 if (! rootmenu->isVisible()) {
2152 blackbox->checkMenu();
2156 } else if (xbutton->button == 4) {
2157 if (getCurrentWorkspaceID() >= getWorkspaceCount() - 1)
2158 changeWorkspaceID(0);
2160 changeWorkspaceID(getCurrentWorkspaceID() + 1);
2162 } else if (xbutton->button == 5) {
2163 if (getCurrentWorkspaceID() == 0)
2164 changeWorkspaceID(getWorkspaceCount() - 1);
2166 changeWorkspaceID(getCurrentWorkspaceID() - 1);
2171 void BScreen::toggleFocusModel(FocusModel model) {
2172 if (model == SloppyFocus) {
2173 saveSloppyFocus(True);
2175 // we're cheating here to save writing the config file 3 times
2176 resource.auto_raise = False;
2177 resource.click_raise = False;
2178 saveSloppyFocus(False);
2185 void BScreen::updateFocusModel()
2187 std::for_each(iconList.begin(), iconList.end(),
2188 std::mem_fun(&BlackboxWindow::ungrabButtons));
2189 std::for_each(windowList.begin(), windowList.end(),
2190 std::mem_fun(&BlackboxWindow::ungrabButtons));
2192 if (! resource.sloppy_focus) {
2193 blackbox->getInput()->add(Button1, 0, BInput::WindowClientPress,
2195 blackbox->getInput()->add(Button1, 0, BInput::WindowClientPress,
2198 if (resource.click_raise)
2199 blackbox->getInput()->add(Button1, 0, BInput::WindowClientPress,
2202 blackbox->getInput()->remove(Button1, 0, BInput::WindowClientPress,
2204 blackbox->getInput()->remove(Button1, 0, BInput::WindowClientPress,
2208 std::for_each(iconList.begin(), iconList.end(),
2209 std::mem_fun(&BlackboxWindow::grabButtons));
2210 std::for_each(windowList.begin(), windowList.end(),
2211 std::mem_fun(&BlackboxWindow::grabButtons));
2215 BTexture BScreen::readDatabaseTexture(const string &rname,
2216 const string &default_color,
2217 Configuration &style) {
2221 if (style.getValue(rname, s))
2222 texture = BTexture(s);
2224 texture.setTexture(BTexture::Solid | BTexture::Flat);
2226 // associate this texture with this screen
2227 texture.setDisplay(getBaseDisplay(), getScreenNumber());
2228 texture.setImageControl(image_control);
2230 if (texture.texture() & BTexture::Solid) {
2231 texture.setColor(readDatabaseColor(rname + ".color",
2232 default_color, style));
2233 texture.setColorTo(readDatabaseColor(rname + ".colorTo",
2234 default_color, style));
2235 } else if (texture.texture() & BTexture::Gradient) {
2236 texture.setColor(readDatabaseColor(rname + ".color",
2237 default_color, style));
2238 texture.setColorTo(readDatabaseColor(rname + ".colorTo",
2239 default_color, style));
2246 BColor BScreen::readDatabaseColor(const string &rname,
2247 const string &default_color,
2248 Configuration &style) {
2251 if (style.getValue(rname, s))
2252 color = BColor(s, getBaseDisplay(), getScreenNumber());
2254 color = BColor(default_color, getBaseDisplay(), getScreenNumber());
2259 XFontSet BScreen::readDatabaseFontSet(const string &rname,
2260 Configuration &style) {
2261 char *defaultFont = "fixed";
2263 bool load_default = True;
2265 XFontSet fontset = 0;
2266 if (style.getValue(rname, s) && (fontset = createFontSet(s)))
2267 load_default = False;
2270 fontset = createFontSet(defaultFont);
2274 i18n(ScreenSet, ScreenDefaultFontLoadFail,
2275 "BScreen::setCurrentStyle(): couldn't load default font.\n"));
2284 XFontStruct *BScreen::readDatabaseFont(const string &rname,
2285 Configuration &style) {
2286 char *defaultFont = "fixed";
2288 bool load_default = False;
2290 XFontStruct *font = 0;
2291 if (style.getValue(rname, s)) {
2292 if ((font = XLoadQueryFont(blackbox->getXDisplay(), s.c_str())) == NULL) {
2294 i18n(ScreenSet, ScreenFontLoadFail,
2295 "BScreen::setCurrentStyle(): couldn't load font '%s'\n"),
2298 load_default = True;
2301 load_default = True;
2305 font = XLoadQueryFont(blackbox->getXDisplay(), defaultFont);
2308 i18n(ScreenSet, ScreenDefaultFontLoadFail,
2309 "BScreen::setCurrentStyle(): couldn't load default font.\n"));
2318 #ifndef HAVE_STRCASESTR
2319 static const char * strcasestr(const char *str, const char *ptn) {
2320 const char *s2, *p2;
2321 for(; *str; str++) {
2322 for(s2=str,p2=ptn; ; s2++,p2++) {
2323 if (! *p2) return str;
2324 if (toupper(*s2) != toupper(*p2)) break;
2329 #endif // HAVE_STRCASESTR
2332 static const char *getFontElement(const char *pattern, char *buf,
2338 va_start(va, bufsiz);
2340 buf[bufsiz-2] = '*';
2341 while((v = va_arg(va, char *)) != NULL) {
2342 p = strcasestr(pattern, v);
2344 strncpy(buf, p+1, bufsiz-2);
2345 p2 = strchr(buf, '-');
2352 strncpy(buf, "*", bufsiz);
2357 static const char *getFontSize(const char *pattern, int *size) {
2359 const char *p2=NULL;
2362 for (p=pattern; 1; p++) {
2364 if (p2!=NULL && n>1 && n<72) {
2365 *size = n; return p2+1;
2367 *size = 16; return NULL;
2369 } else if (*p=='-') {
2370 if (n>1 && n<72 && p2!=NULL) {
2375 } else if (*p>='0' && *p<='9' && p2!=NULL) {
2385 XFontSet BScreen::createFontSet(const string &fontname) {
2387 char **missing, *def = "-";
2388 int nmissing, pixel_size = 0, buf_size = 0;
2389 char weight[FONT_ELEMENT_SIZE], slant[FONT_ELEMENT_SIZE];
2391 fs = XCreateFontSet(blackbox->getXDisplay(),
2392 fontname.c_str(), &missing, &nmissing, &def);
2393 if (fs && (! nmissing))
2396 const char *nfontname = fontname.c_str();
2397 #ifdef HAVE_SETLOCALE
2399 if (nmissing) XFreeStringList(missing);
2401 setlocale(LC_CTYPE, "C");
2402 fs = XCreateFontSet(blackbox->getXDisplay(), fontname.c_str(),
2403 &missing, &nmissing, &def);
2404 setlocale(LC_CTYPE, "");
2406 #endif // HAVE_SETLOCALE
2409 XFontStruct **fontstructs;
2411 XFontsOfFontSet(fs, &fontstructs, &fontnames);
2412 nfontname = fontnames[0];
2415 getFontElement(nfontname, weight, FONT_ELEMENT_SIZE,
2416 "-medium-", "-bold-", "-demibold-", "-regular-", NULL);
2417 getFontElement(nfontname, slant, FONT_ELEMENT_SIZE,
2418 "-r-", "-i-", "-o-", "-ri-", "-ro-", NULL);
2419 getFontSize(nfontname, &pixel_size);
2421 if (! strcmp(weight, "*"))
2422 strncpy(weight, "medium", FONT_ELEMENT_SIZE);
2423 if (! strcmp(slant, "*"))
2424 strncpy(slant, "r", FONT_ELEMENT_SIZE);
2427 else if (pixel_size > 97)
2430 buf_size = strlen(nfontname) + (FONT_ELEMENT_SIZE * 2) + 64;
2431 char *pattern2 = new char[buf_size];
2434 "-*-*-%s-%s-*-*-%d-*-*-*-*-*-*-*,"
2435 "-*-*-*-*-*-*-%d-*-*-*-*-*-*-*,*",
2436 nfontname, weight, slant, pixel_size, pixel_size);
2437 nfontname = pattern2;
2440 XFreeStringList(missing);
2442 XFreeFontSet(blackbox->getXDisplay(), fs);
2444 fs = XCreateFontSet(blackbox->getXDisplay(), nfontname, &missing,