1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 04:20:27 +01:00
Files
wmaker/src/screen.c
Iain Patterson 07a0639c93 Don't shrink icons in switchpanel.
Icons in the switchpanel are constrained to the value of the IconSize
preference but the grid in which they are arranged is fixed at 64 pixels.
If IconSize is less than 64x64 the panel will show smaller icons with a
wide spacing, which looks pretty stupid.

Fix it by forcing the switchpanel to attempt to load images at the size
it's going to use.  The icon it actually gets may of course still be
smaller.
2012-02-16 09:13:01 +00:00

1111 lines
31 KiB
C

/* screen.c - screen management
*
* Window Maker window manager
*
* Copyright (c) 1997-2003 Alfredo K. Kojima
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "wconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif
#ifdef KEEP_XKB_LOCK_STATUS
#include <X11/XKBlib.h>
#endif /* KEEP_XKB_LOCK_STATUS */
#ifdef HAVE_XRANDR
#include <X11/extensions/Xrandr.h>
#endif
#include <wraster.h>
#include "WindowMaker.h"
#include "def_pixmaps.h"
#include "screen.h"
#include "texture.h"
#include "pixmap.h"
#include "menu.h"
#include "funcs.h"
#include "actions.h"
#include "properties.h"
#include "dock.h"
#include "resources.h"
#include "workspace.h"
#include "session.h"
#include "balloon.h"
#include "geomview.h"
#include "wmspec.h"
#include "xinerama.h"
#include <WINGs/WUtil.h>
#include "defaults.h"
#define EVENT_MASK (LeaveWindowMask|EnterWindowMask|PropertyChangeMask\
|SubstructureNotifyMask|PointerMotionMask \
|SubstructureRedirectMask|ButtonPressMask|ButtonReleaseMask\
|KeyPressMask|KeyReleaseMask)
/**** Global variables ****/
extern Cursor wCursor[WCUR_LAST];
extern WPreferences wPreferences;
extern Atom _XA_WINDOWMAKER_STATE;
extern Atom _XA_WINDOWMAKER_NOTICEBOARD;
extern int wScreenCount;
#ifdef KEEP_XKB_LOCK_STATUS
extern int wXkbSupported;
#endif
#ifdef HAVE_XRANDR
extern int has_randr;
#endif
extern WDDomain *WDWindowMaker;
/**** Local ****/
#define STIPPLE_WIDTH 2
#define STIPPLE_HEIGHT 2
static char STIPPLE_DATA[] = { 0x02, 0x01 };
static int CantManageScreen = 0;
static WMPropList *dApplications = NULL;
static WMPropList *dWorkspace;
static WMPropList *dDock;
static WMPropList *dClip;
static void make_keys(void)
{
if (dApplications != NULL)
return;
dApplications = WMCreatePLString("Applications");
dWorkspace = WMCreatePLString("Workspace");
dDock = WMCreatePLString("Dock");
dClip = WMCreatePLString("Clip");
}
/*
*----------------------------------------------------------------------
* alreadyRunningError--
* X error handler used to catch errors when trying to do
* XSelectInput() on the root window. These errors probably mean that
* there already is some other window manager running.
*
* Returns:
* Nothing, unless something really evil happens...
*
* Side effects:
* CantManageScreen is set to 1;
*----------------------------------------------------------------------
*/
static int alreadyRunningError(Display * dpy, XErrorEvent * error)
{
CantManageScreen = 1;
return -1;
}
/*
*----------------------------------------------------------------------
* allocButtonPixmaps--
* Allocate pixmaps used on window operation buttons (those in the
* titlebar). The pixmaps are linked to the program. If XPM is supported
* XPM pixmaps are used otherwise, equivalent bitmaps are used.
*
* Returns:
* Nothing
*
* Side effects:
* Allocates shared pixmaps for the screen. These pixmaps should
* not be freed by anybody.
*----------------------------------------------------------------------
*/
static void allocButtonPixmaps(WScreen * scr)
{
WPixmap *pix;
/* create predefined pixmaps */
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_CLOSE_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_CLOSE_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_CLOSE] = pix;
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_BROKEN_CLOSE_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_BROKEN_CLOSE_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_BROKENCLOSE] = pix;
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_ICONIFY_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_ICONIFY_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_ICONIFY] = pix;
#ifdef XKB_BUTTON_HINT
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP1_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP1_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_XKBGROUP1] = pix;
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP2_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP2_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_XKBGROUP2] = pix;
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP3_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP3_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_XKBGROUP3] = pix;
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_XKBGROUP4_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_XKBGROUP4_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_XKBGROUP4] = pix;
#endif
if (wPreferences.new_style == TS_NEXT) {
pix = wPixmapCreateFromXPMData(scr, NEXT_KILL_XPM);
} else {
pix = wPixmapCreateFromXPMData(scr, PRED_KILL_XPM);
}
if (pix)
pix->shared = 1;
scr->b_pixmaps[WBUT_KILL] = pix;
}
static void draw_dot(WScreen * scr, Drawable d, int x, int y, GC gc)
{
XSetForeground(dpy, gc, scr->black_pixel);
XDrawLine(dpy, d, gc, x, y, x + 1, y);
XDrawPoint(dpy, d, gc, x, y + 1);
XSetForeground(dpy, gc, scr->white_pixel);
XDrawLine(dpy, d, gc, x + 2, y, x + 2, y + 1);
XDrawPoint(dpy, d, gc, x + 1, y + 1);
}
static WPixmap *make3Dots(WScreen * scr)
{
WPixmap *wpix;
GC gc2, gc;
XGCValues gcv;
Pixmap pix, mask;
gc = scr->copy_gc;
pix = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, scr->w_depth);
XSetForeground(dpy, gc, scr->black_pixel);
XFillRectangle(dpy, pix, gc, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
XSetForeground(dpy, gc, scr->white_pixel);
draw_dot(scr, pix, 4, wPreferences.icon_size - 6, gc);
draw_dot(scr, pix, 9, wPreferences.icon_size - 6, gc);
draw_dot(scr, pix, 14, wPreferences.icon_size - 6, gc);
mask = XCreatePixmap(dpy, scr->w_win, wPreferences.icon_size, wPreferences.icon_size, 1);
gcv.foreground = 0;
gcv.graphics_exposures = False;
gc2 = XCreateGC(dpy, mask, GCForeground | GCGraphicsExposures, &gcv);
XFillRectangle(dpy, mask, gc2, 0, 0, wPreferences.icon_size, wPreferences.icon_size);
XSetForeground(dpy, gc2, 1);
XFillRectangle(dpy, mask, gc2, 4, wPreferences.icon_size - 6, 3, 2);
XFillRectangle(dpy, mask, gc2, 9, wPreferences.icon_size - 6, 3, 2);
XFillRectangle(dpy, mask, gc2, 14, wPreferences.icon_size - 6, 3, 2);
XFreeGC(dpy, gc2);
wpix = wPixmapCreate(scr, pix, mask);
wpix->shared = 1;
return wpix;
}
static void allocGCs(WScreen * scr)
{
XGCValues gcv;
XColor color;
int gcm;
scr->stipple_bitmap = XCreateBitmapFromData(dpy, scr->w_win, STIPPLE_DATA, STIPPLE_WIDTH, STIPPLE_HEIGHT);
gcv.stipple = scr->stipple_bitmap;
gcv.foreground = scr->white_pixel;
gcv.fill_style = FillStippled;
gcv.graphics_exposures = False;
gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
scr->stipple_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
/* selected icon border GCs */
gcv.function = GXcopy;
gcv.foreground = scr->white_pixel;
gcv.background = scr->black_pixel;
gcv.line_width = 1;
gcv.line_style = LineDoubleDash;
gcv.fill_style = FillSolid;
gcv.dash_offset = 0;
gcv.dashes = 4;
gcv.graphics_exposures = False;
gcm = GCFunction | GCGraphicsExposures;
gcm |= GCForeground | GCBackground;
gcm |= GCLineWidth | GCLineStyle;
gcm |= GCFillStyle;
gcm |= GCDashOffset | GCDashList;
scr->icon_select_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
scr->menu_title_color[0] = WMRetainColor(scr->white);
/* don't retain scr->black here because we may alter its alpha */
scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
/* frame GC */
wGetColor(scr, DEF_FRAME_COLOR, &color);
gcv.function = GXxor;
/* this will raise the probability of the XORed color being different
* of the original color in PseudoColor when not all color cells are
* initialized */
if (DefaultVisual(dpy, scr->screen)->class == PseudoColor)
gcv.plane_mask = (1 << (scr->depth - 1)) | 1;
else
gcv.plane_mask = AllPlanes;
gcv.foreground = color.pixel;
if (gcv.foreground == 0)
gcv.foreground = 1;
gcv.line_width = DEF_FRAME_THICKNESS;
gcv.subwindow_mode = IncludeInferiors;
gcv.graphics_exposures = False;
scr->frame_gc = XCreateGC(dpy, scr->root_win, GCForeground | GCGraphicsExposures
| GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
/* line GC */
gcv.foreground = color.pixel;
if (gcv.foreground == 0)
/* XOR:ing with a zero is not going to be of much use, so
in that case, we somewhat arbitrarily xor with 17 instead. */
gcv.foreground = 17;
gcv.function = GXxor;
gcv.subwindow_mode = IncludeInferiors;
gcv.line_width = 1;
gcv.cap_style = CapRound;
gcv.graphics_exposures = False;
gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth | GCCapStyle | GCGraphicsExposures;
scr->line_gc = XCreateGC(dpy, scr->root_win, gcm, &gcv);
scr->line_pixel = gcv.foreground;
/* copy GC */
gcv.foreground = scr->white_pixel;
gcv.background = scr->black_pixel;
gcv.graphics_exposures = False;
scr->copy_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
/* misc drawing GC */
gcv.graphics_exposures = False;
gcm = GCGraphicsExposures;
scr->draw_gc = XCreateGC(dpy, scr->w_win, gcm, &gcv);
assert(scr->stipple_bitmap != None);
/* mono GC */
scr->mono_gc = XCreateGC(dpy, scr->stipple_bitmap, gcm, &gcv);
}
static void createPixmaps(WScreen * scr)
{
WPixmap *pix;
RImage *image;
/* load pixmaps */
pix = wPixmapCreateFromXBMData(scr, (char *)MENU_RADIO_INDICATOR_XBM_DATA,
(char *)MENU_RADIO_INDICATOR_XBM_DATA,
MENU_RADIO_INDICATOR_XBM_SIZE,
MENU_RADIO_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
if (pix != NULL)
pix->shared = 1;
scr->menu_radio_indicator = pix;
pix = wPixmapCreateFromXBMData(scr, (char *)MENU_CHECK_INDICATOR_XBM_DATA,
(char *)MENU_CHECK_INDICATOR_XBM_DATA,
MENU_CHECK_INDICATOR_XBM_SIZE,
MENU_CHECK_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
if (pix != NULL)
pix->shared = 1;
scr->menu_check_indicator = pix;
pix = wPixmapCreateFromXBMData(scr, (char *)MENU_MINI_INDICATOR_XBM_DATA,
(char *)MENU_MINI_INDICATOR_XBM_DATA,
MENU_MINI_INDICATOR_XBM_SIZE,
MENU_MINI_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
if (pix != NULL)
pix->shared = 1;
scr->menu_mini_indicator = pix;
pix = wPixmapCreateFromXBMData(scr, (char *)MENU_HIDE_INDICATOR_XBM_DATA,
(char *)MENU_HIDE_INDICATOR_XBM_DATA,
MENU_HIDE_INDICATOR_XBM_SIZE,
MENU_HIDE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
if (pix != NULL)
pix->shared = 1;
scr->menu_hide_indicator = pix;
pix = wPixmapCreateFromXBMData(scr, (char *)MENU_SHADE_INDICATOR_XBM_DATA,
(char *)MENU_SHADE_INDICATOR_XBM_DATA,
MENU_SHADE_INDICATOR_XBM_SIZE,
MENU_SHADE_INDICATOR_XBM_SIZE, scr->black_pixel, scr->white_pixel);
if (pix != NULL)
pix->shared = 1;
scr->menu_shade_indicator = pix;
image = wDefaultGetImage(scr, "Logo", "WMPanel", wPreferences.icon_size);
if (!image) {
wwarning(_("could not load logo image for panels: %s"), RMessageForError(RErrorCode));
} else {
WMSetApplicationIconImage(scr->wmscreen, image);
RReleaseImage(image);
}
scr->dock_dots = make3Dots(scr);
/* titlebar button pixmaps */
allocButtonPixmaps(scr);
}
/*
*----------------------------------------------------------------------
* createInternalWindows--
* Creates some windows used internally by the program. One to
* receive input focus when no other window can get it and another
* to display window geometry information during window resize/move.
*
* Returns:
* Nothing
*
* Side effects:
* Windows are created and some colors are allocated for the
* window background.
*----------------------------------------------------------------------
*/
static void createInternalWindows(WScreen * scr)
{
int vmask;
XSetWindowAttributes attribs;
/* InputOnly window to get the focus when no other window can get it */
vmask = CWEventMask | CWOverrideRedirect;
attribs.event_mask = KeyPressMask | FocusChangeMask;
attribs.override_redirect = True;
scr->no_focus_win = XCreateWindow(dpy, scr->root_win, -10, -10, 4, 4, 0, 0,
InputOnly, CopyFromParent, vmask, &attribs);
XSelectInput(dpy, scr->no_focus_win, KeyPressMask | KeyReleaseMask);
XMapWindow(dpy, scr->no_focus_win);
XSetInputFocus(dpy, scr->no_focus_win, RevertToParent, CurrentTime);
/* shadow window for dock buttons */
vmask = CWBorderPixel | CWBackPixmap | CWBackPixel | CWCursor | CWSaveUnder | CWOverrideRedirect;
attribs.border_pixel = scr->black_pixel;
attribs.save_under = True;
attribs.override_redirect = True;
attribs.background_pixmap = None;
attribs.background_pixel = scr->white_pixel;
attribs.cursor = wCursor[WCUR_DEFAULT];
vmask |= CWColormap;
attribs.colormap = scr->w_colormap;
scr->dock_shadow =
XCreateWindow(dpy, scr->root_win, 0, 0, wPreferences.icon_size,
wPreferences.icon_size, 0, scr->w_depth, CopyFromParent, scr->w_visual, vmask, &attribs);
/* workspace name balloon for clip */
vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
attribs.save_under = True;
attribs.override_redirect = True;
attribs.colormap = scr->w_colormap;
attribs.background_pixel = scr->icon_back_texture->normal.pixel;
attribs.border_pixel = 0; /* do not care */
scr->clip_balloon =
XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
CopyFromParent, scr->w_visual, vmask, &attribs);
/* workspace name */
vmask = CWBackPixel | CWSaveUnder | CWOverrideRedirect | CWColormap | CWBorderPixel;
attribs.save_under = True;
attribs.override_redirect = True;
attribs.colormap = scr->w_colormap;
attribs.background_pixel = scr->icon_back_texture->normal.pixel;
attribs.border_pixel = 0; /* do not care */
scr->workspace_name =
XCreateWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, scr->w_depth,
CopyFromParent, scr->w_visual, vmask, &attribs);
/*
* If the window is clicked without having ButtonPress selected, the
* resulting event will have event.xbutton.window == root.
*/
XSelectInput(dpy, scr->clip_balloon, ButtonPressMask);
}
#if 0
static Bool aquireManagerSelection(WScreen * scr)
{
char buffer[32];
XEvent ev;
Time timestamp;
snprintf(buffer, sizeof(buffer), "WM_S%i", scr->screen);
scr->managerAtom = XInternAtom(dpy, buffer, False);
/* for race-conditions... */
XGrabServer(dpy);
/* if there is another manager running, don't try to replace it
* (for now, at least) */
if (XGetSelectionOwner(dpy, scr->managerAtom) != None) {
XUngrabServer(dpy);
return False;
}
/* become the manager for this screen */
scr->managerWindow = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 1, 1, 0, 0, 0);
XSelectInput(dpy, scr->managerWindow, PropertyChangeMask);
/* get a timestamp */
XChangeProperty(dpy, scr->managerWindow, scr->managerAtom, XA_INTEGER, 32, PropModeAppend, NULL, 0);
while (1) {
XWindowEvent(dpy, scr->managerWindow, &ev);
if (ev.type == PropertyNotify) {
timestamp = ev.xproperty.time;
break;
}
}
XSelectInput(dpy, scr->managerWindow, NoEvents);
XDeleteProperty(dpy, scr->managerWindow, scr->managerAtom);
XSetSelectionOwner(dpy, scr->managerAtom, scr->managerWindow, CurrentTime);
XUngrabServer(dpy);
/* announce our arrival */
ev.xclient.type = ClientMessage;
ev.xclient.message_type = XInternAtom(dpy, "MANAGER", False);
ev.xclient.destination = scr->root_win;
ev.xclient.format = 32;
ev.xclient.data.l[0] = timestamp;
ev.xclient.data.l[1] = scr->managerAtom;
ev.xclient.data.l[2] = scr->managerWindow;
ev.xclient.data.l[3] = 0;
ev.xclient.data.l[4] = 0;
XSendEvent(dpy, scr->root_win, False, StructureNotify, &ev);
XSync(dpy, False);
return True;
}
#endif
/*
*----------------------------------------------------------------------
* wScreenInit--
* Initializes the window manager for the given screen and
* allocates a WScreen descriptor for it. Many resources are allocated
* for the screen and the root window is setup appropriately.
*
* Returns:
* The WScreen descriptor for the screen.
*
* Side effects:
* Many resources are allocated and the IconSize property is
* set on the root window.
* The program can be aborted if some fatal error occurs.
*
* TODO: User specifiable visual.
*----------------------------------------------------------------------
*/
WScreen *wScreenInit(int screen_number)
{
WScreen *scr;
XIconSize icon_size[1];
RContextAttributes rattr;
long event_mask;
XErrorHandler oldHandler;
int i;
scr = wmalloc(sizeof(WScreen));
memset(scr, 0, sizeof(WScreen));
scr->stacking_list = WMCreateTreeBag();
/* initialize globals */
scr->screen = screen_number;
scr->root_win = RootWindow(dpy, screen_number);
scr->depth = DefaultDepth(dpy, screen_number);
scr->colormap = DefaultColormap(dpy, screen_number);
scr->scr_width = WidthOfScreen(ScreenOfDisplay(dpy, screen_number));
scr->scr_height = HeightOfScreen(ScreenOfDisplay(dpy, screen_number));
wInitXinerama(scr);
scr->usableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
scr->totalUsableArea = (WArea *) wmalloc(sizeof(WArea) * wXineramaHeads(scr));
for (i = 0; i < wXineramaHeads(scr); ++i) {
WMRect rect = wGetRectForHead(scr, i);
scr->usableArea[i].x1 = scr->totalUsableArea[i].x1 = rect.pos.x;
scr->usableArea[i].y1 = scr->totalUsableArea[i].y1 = rect.pos.y;
scr->usableArea[i].x2 = scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
scr->usableArea[i].y2 = scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
}
scr->fakeGroupLeaders = WMCreateArray(16);
#if 0
if (!aquireManagerSelection(scr)) {
wfree(scr);
return NULL;
}
#endif
CantManageScreen = 0;
oldHandler = XSetErrorHandler((XErrorHandler) alreadyRunningError);
event_mask = EVENT_MASK;
if (wPreferences.disable_root_mouse) {
event_mask &= ~(ButtonPressMask | ButtonReleaseMask);
}
XSelectInput(dpy, scr->root_win, event_mask);
#ifdef KEEP_XKB_LOCK_STATUS
/* Only GroupLock doesn't work correctly in my system since right-alt
* can change mode while holding it too - ]d
*/
if (wXkbSupported) {
XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask, XkbStateNotifyMask);
}
#endif /* KEEP_XKB_LOCK_STATUS */
#ifdef HAVE_XRANDR
if (has_randr)
XRRSelectInput(dpy, scr->root_win, RRScreenChangeNotifyMask);
#endif
XSync(dpy, False);
XSetErrorHandler(oldHandler);
if (CantManageScreen) {
wfree(scr);
return NULL;
}
XDefineCursor(dpy, scr->root_win, wCursor[WCUR_ROOT]);
/* screen descriptor for raster graphic library */
rattr.flags = RC_RenderMode | RC_ColorsPerChannel | RC_StandardColormap;
rattr.render_mode = wPreferences.no_dithering ? RBestMatchRendering : RDitheredRendering;
/* if the std colormap stuff works ok, this will be ignored */
rattr.colors_per_channel = wPreferences.cmap_size;
if (rattr.colors_per_channel < 2)
rattr.colors_per_channel = 2;
/* will only be accounted for in PseudoColor */
if (wPreferences.flags.create_stdcmap) {
rattr.standard_colormap_mode = RCreateStdColormap;
} else {
rattr.standard_colormap_mode = RUseStdColormap;
}
if (getWVisualID(screen_number) >= 0) {
rattr.flags |= RC_VisualID;
rattr.visualid = getWVisualID(screen_number);
}
scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
if (!scr->rcontext && RErrorCode == RERR_STDCMAPFAIL) {
wwarning("%s", RMessageForError(RErrorCode));
rattr.flags &= ~RC_StandardColormap;
rattr.standard_colormap_mode = RUseStdColormap;
scr->rcontext = RCreateContext(dpy, screen_number, &rattr);
}
if (!scr->rcontext) {
wwarning(_("could not initialize graphics library context: %s"), RMessageForError(RErrorCode));
wAbort(False);
} else {
char **formats;
int i = 0;
formats = RSupportedFileFormats();
if (formats) {
for (i = 0; formats[i] != NULL; i++) {
if (strcmp(formats[i], "TIFF") == 0) {
scr->flags.supports_tiff = 1;
break;
}
}
}
}
scr->w_win = scr->rcontext->drawable;
scr->w_visual = scr->rcontext->visual;
scr->w_depth = scr->rcontext->depth;
scr->w_colormap = scr->rcontext->cmap;
/* create screen descriptor for WINGs */
scr->wmscreen = WMCreateScreenWithRContext(dpy, screen_number, scr->rcontext);
if (!scr->wmscreen) {
wfatal(_("could not initialize WINGs widget set"));
return NULL;
}
scr->black = WMBlackColor(scr->wmscreen);
scr->white = WMWhiteColor(scr->wmscreen);
scr->gray = WMGrayColor(scr->wmscreen);
scr->darkGray = WMDarkGrayColor(scr->wmscreen);
scr->black_pixel = WMColorPixel(scr->black); /*scr->rcontext->black; */
scr->white_pixel = WMColorPixel(scr->white); /*scr->rcontext->white; */
scr->light_pixel = WMColorPixel(scr->gray);
scr->dark_pixel = WMColorPixel(scr->darkGray);
{
XColor xcol;
/* frame boder color */
wGetColor(scr, FRAME_BORDER_COLOR, &xcol);
scr->frame_border_pixel = xcol.pixel;
}
/* create GCs with default values */
allocGCs(scr);
/* for our window manager info notice board. Need to
* create before reading the defaults, because it will be used there.
*/
scr->info_window = XCreateSimpleWindow(dpy, scr->root_win, 0, 0, 10, 10, 0, 0, 0);
/* read defaults for this screen */
wReadDefaults(scr, WDWindowMaker->dictionary);
createInternalWindows(scr);
wNETWMInitStuff(scr);
/* create initial workspace */
wWorkspaceNew(scr);
/* create shared pixmaps */
createPixmaps(scr);
/* set icon sizes we can accept from clients */
icon_size[0].min_width = 8;
icon_size[0].min_height = 8;
icon_size[0].max_width = wPreferences.icon_size - 4;
icon_size[0].max_height = wPreferences.icon_size - 4;
icon_size[0].width_inc = 1;
icon_size[0].height_inc = 1;
XSetIconSizes(dpy, scr->root_win, icon_size, 1);
/* setup WindowMaker protocols property in the root window */
PropSetWMakerProtocols(scr->root_win);
/* setup our noticeboard */
XChangeProperty(dpy, scr->info_window, _XA_WINDOWMAKER_NOTICEBOARD,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
XChangeProperty(dpy, scr->root_win, _XA_WINDOWMAKER_NOTICEBOARD,
XA_WINDOW, 32, PropModeReplace, (unsigned char *)&scr->info_window, 1);
#ifdef BALLOON_TEXT
/* initialize balloon text stuff */
wBalloonInitialize(scr);
#endif
scr->info_text_font = WMBoldSystemFontOfSize(scr->wmscreen, 12);
scr->tech_draw_font = XLoadQueryFont(dpy, "-adobe-helvetica-bold-r-*-*-12-*-*-*-*-*-*-*");
if (!scr->tech_draw_font)
scr->tech_draw_font = XLoadQueryFont(dpy, "fixed");
scr->gview = WCreateGeometryView(scr->wmscreen);
WMRealizeWidget(scr->gview);
wScreenUpdateUsableArea(scr);
return scr;
}
void wScreenUpdateUsableArea(WScreen * scr)
{
/*
* scr->totalUsableArea[] will become the usableArea used for Windowplacement,
* scr->usableArea[] will be used for iconplacement, hence no iconyard nor
* border.
*/
WArea area;
int i, dock_head;
unsigned long best_area, tmp_area;
unsigned int size, position;
dock_head = scr->xine_info.primary_head;
best_area = 0;
size = wPreferences.workspace_border_size;
position = wPreferences.workspace_border_position;
if (scr->dock) {
WMRect rect;
rect.pos.x = scr->dock->x_pos;
rect.pos.y = scr->dock->y_pos;
rect.size.width = wPreferences.icon_size;
rect.size.height = wPreferences.icon_size;
dock_head = wGetHeadForRect(scr, rect);
}
for (i = 0; i < wXineramaHeads(scr); ++i) {
WMRect rect = wGetRectForHead(scr, i);
scr->totalUsableArea[i].x1 = rect.pos.x;
scr->totalUsableArea[i].y1 = rect.pos.y;
scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
if (scr->dock && dock_head == i && (!scr->dock->lowered || wPreferences.no_window_over_dock)) {
int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
if (scr->dock->on_right_side) {
scr->totalUsableArea[i].x2 -= offset;
} else {
scr->totalUsableArea[i].x1 += offset;
}
}
if (wNETWMGetUsableArea(scr, i, &area)) {
scr->totalUsableArea[i].x1 = WMAX(scr->totalUsableArea[i].x1, area.x1);
scr->totalUsableArea[i].y1 = WMAX(scr->totalUsableArea[i].y1, area.y1);
scr->totalUsableArea[i].x2 = WMIN(scr->totalUsableArea[i].x2, area.x2);
scr->totalUsableArea[i].y2 = WMIN(scr->totalUsableArea[i].y2, area.y2);
}
scr->usableArea[i] = scr->totalUsableArea[i];
#if 0
printf("usableArea[%d]: %d %d %d %d\n", i,
scr->usableArea[i].x1, scr->usableArea[i].x2, scr->usableArea[i].y1, scr->usableArea[i].y2);
#endif
if (wPreferences.no_window_over_icons) {
if (wPreferences.icon_yard & IY_VERT) {
if (wPreferences.icon_yard & IY_RIGHT) {
scr->totalUsableArea[i].x2 -= wPreferences.icon_size;
} else {
scr->totalUsableArea[i].x1 += wPreferences.icon_size;
}
} else {
if (wPreferences.icon_yard & IY_TOP) {
scr->totalUsableArea[i].y1 += wPreferences.icon_size;
} else {
scr->totalUsableArea[i].y2 -= wPreferences.icon_size;
}
}
}
if (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1 < rect.size.width / 2) {
scr->totalUsableArea[i].x1 = rect.pos.x;
scr->totalUsableArea[i].x2 = rect.pos.x + rect.size.width;
}
if (scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1 < rect.size.height / 2) {
scr->totalUsableArea[i].y1 = rect.pos.y;
scr->totalUsableArea[i].y2 = rect.pos.y + rect.size.height;
}
tmp_area = (scr->totalUsableArea[i].x2 - scr->totalUsableArea[i].x1) *
(scr->totalUsableArea[i].y2 - scr->totalUsableArea[i].y1);
if (tmp_area > best_area) {
best_area = tmp_area;
area = scr->totalUsableArea[i];
}
if (size > 0 && position != WB_NONE) {
if (position & WB_LEFTRIGHT) {
scr->totalUsableArea[i].x1 += size;
scr->totalUsableArea[i].x2 -= size;
}
if (position & WB_TOPBOTTOM) {
scr->totalUsableArea[i].y1 += size;
scr->totalUsableArea[i].y2 -= size;
}
}
}
if (wPreferences.auto_arrange_icons)
wArrangeIcons(scr, True);
}
void wScreenRestoreState(WScreen * scr)
{
WMPropList *state;
char *path;
OpenRootMenu(scr, -10000, -10000, False);
wMenuUnmap(scr->root_menu);
make_keys();
if (wScreenCount == 1) {
path = wdefaultspathfordomain("WMState");
} else {
char buf[16];
snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
path = wdefaultspathfordomain(buf);
}
scr->session_state = WMReadPropListFromFile(path);
wfree(path);
if (!scr->session_state && wScreenCount > 1) {
path = wdefaultspathfordomain("WMState");
scr->session_state = WMReadPropListFromFile(path);
wfree(path);
}
if (!scr->session_state) {
scr->session_state = WMCreatePLDictionary(NULL, NULL);
}
if (!wPreferences.flags.nodock) {
state = WMGetFromPLDictionary(scr->session_state, dDock);
scr->dock = wDockRestoreState(scr, state, WM_DOCK);
}
if (!wPreferences.flags.noclip) {
state = WMGetFromPLDictionary(scr->session_state, dClip);
scr->clip_icon = wClipRestoreState(scr, state);
}
wWorkspaceRestoreState(scr);
wScreenUpdateUsableArea(scr);
}
void wScreenSaveState(WScreen * scr)
{
WWindow *wwin;
char *str;
WMPropList *old_state, *foo;
make_keys();
/* save state of windows */
wwin = scr->focused_window;
while (wwin) {
wWindowSaveState(wwin);
wwin = wwin->prev;
}
if (wPreferences.flags.noupdates)
return;
old_state = scr->session_state;
scr->session_state = WMCreatePLDictionary(NULL, NULL);
WMPLSetCaseSensitive(True);
/* save dock state to file */
if (!wPreferences.flags.nodock) {
wDockSaveState(scr, old_state);
} else {
if ((foo = WMGetFromPLDictionary(old_state, dDock)) != NULL) {
WMPutInPLDictionary(scr->session_state, dDock, foo);
}
}
if (!wPreferences.flags.noclip) {
wClipSaveState(scr);
} else {
if ((foo = WMGetFromPLDictionary(old_state, dClip)) != NULL) {
WMPutInPLDictionary(scr->session_state, dClip, foo);
}
}
wWorkspaceSaveState(scr, old_state);
if (wPreferences.save_session_on_exit) {
wSessionSaveState(scr);
} else {
if ((foo = WMGetFromPLDictionary(old_state, dApplications)) != NULL) {
WMPutInPLDictionary(scr->session_state, dApplications, foo);
}
if ((foo = WMGetFromPLDictionary(old_state, dWorkspace)) != NULL) {
WMPutInPLDictionary(scr->session_state, dWorkspace, foo);
}
}
/* clean up */
WMPLSetCaseSensitive(False);
wMenuSaveState(scr);
if (wScreenCount == 1) {
str = wdefaultspathfordomain("WMState");
} else {
char buf[16];
snprintf(buf, sizeof(buf), "WMState.%i", scr->screen);
str = wdefaultspathfordomain(buf);
}
if (!WMWritePropListToFile(scr->session_state, str)) {
werror(_("could not save session state in %s"), str);
}
wfree(str);
WMReleasePropList(old_state);
}
int wScreenBringInside(WScreen * scr, int *x, int *y, int width, int height)
{
int moved = 0;
int tol_w, tol_h;
/*
* With respect to the head that contains most of the window.
*/
int sx1, sy1, sx2, sy2;
WMRect rect;
int head, flags;
rect.pos.x = *x;
rect.pos.y = *y;
rect.size.width = width;
rect.size.height = height;
head = wGetRectPlacementInfo(scr, rect, &flags);
rect = wGetRectForHead(scr, head);
sx1 = rect.pos.x;
sy1 = rect.pos.y;
sx2 = sx1 + rect.size.width;
sy2 = sy1 + rect.size.height;
#if 0 /* NOTE: gives funky group movement */
if (flags & XFLAG_MULTIPLE) {
/*
* since we span multiple heads, pull window totaly inside
*/
if (*x < sx1)
*x = sx1, moved = 1;
else if (*x + width > sx2)
*x = sx2 - width, moved = 1;
if (*y < sy1)
*y = sy1, moved = 1;
else if (*y + height > sy2)
*y = sy2 - height, moved = 1;
return moved;
}
#endif
if (width > 20)
tol_w = width / 2;
else
tol_w = 20;
if (height > 20)
tol_h = height / 2;
else
tol_h = 20;
if (*x + width < sx1 + 10)
*x = sx1 - tol_w, moved = 1;
else if (*x >= sx2 - 10)
*x = sx2 - tol_w - 1, moved = 1;
if (*y < sy1 - height + 10)
*y = sy1 - tol_h, moved = 1;
else if (*y >= sy2 - 10)
*y = sy2 - tol_h - 1, moved = 1;
return moved;
}
int wScreenKeepInside(WScreen * scr, int *x, int *y, int width, int height)
{
int moved = 0;
int sx1, sy1, sx2, sy2;
WMRect rect;
int head;
rect.pos.x = *x;
rect.pos.y = *y;
rect.size.width = width;
rect.size.height = height;
head = wGetHeadForRect(scr, rect);
rect = wGetRectForHead(scr, head);
sx1 = rect.pos.x;
sy1 = rect.pos.y;
sx2 = sx1 + rect.size.width;
sy2 = sy1 + rect.size.height;
if (*x < sx1)
*x = sx1, moved = 1;
else if (*x + width > sx2)
*x = sx2 - width, moved = 1;
if (*y < sy1)
*y = sy1, moved = 1;
else if (*y + height > sy2)
*y = sy2 - height, moved = 1;
return moved;
}