mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 20:38:08 +01:00
1778 lines
41 KiB
C
1778 lines
41 KiB
C
/* kwm.c-- stuff for support for kwm hints
|
|
*
|
|
* Window Maker window manager
|
|
*
|
|
* Copyright (c) 1998, 1999 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
|
* USA.
|
|
*/
|
|
|
|
/*
|
|
*
|
|
* Supported stuff:
|
|
* ================
|
|
*
|
|
* kfm icon selection from krootbgwm
|
|
*
|
|
* kwm.h function/method Notes
|
|
*----------------------------------------------------------------------------
|
|
* setUnsavedDataHint() currently, only gives visual clue that
|
|
* there is unsaved data (broken X close button)
|
|
* setSticky()
|
|
* setIcon() std X thing...
|
|
* setDecoration()
|
|
* logout()
|
|
* refreshScreen()
|
|
* setWmCommand() std X thing
|
|
* currentDesktop()
|
|
* setKWMModule()
|
|
*
|
|
* isKWMInitialized() not trustworthy
|
|
* activeWindow() dunno it's use, but since it's easy to
|
|
* implement it won't hurt to support
|
|
* switchToDesktop()
|
|
* (set/get)WindowRegion()
|
|
* (set)numberOfDesktops() KDE limits to 32, but wmaker is virtually
|
|
* unlimited. May raise some incompatibility
|
|
* in badly written KDE modules?
|
|
* (set/get)DesktopName()
|
|
* sendKWMCommand() also does the message relay thing
|
|
* desktop()
|
|
* geometryRestore()
|
|
* isIconified()
|
|
* isMaximized()
|
|
* isSticky()
|
|
* moveToDesktop() WARNING: evil mechanism
|
|
* setGeometryRestore() WARNING: evil mechanism
|
|
* setMaximize() woo hoo! wanna race?
|
|
* setIconify() BAH!: why reinvent the f'ing wheel!?
|
|
* its even broken!!!
|
|
* move() std X thing
|
|
* setGeometry() std X thing
|
|
* close() std X thing
|
|
* activate()
|
|
* activateInternal()
|
|
* raise() std X thing
|
|
* lower() std X thing
|
|
* prepareForSwallowing() std X thing
|
|
* doNotManage() klugy thing...
|
|
* getBlablablaString()
|
|
* setKWMDockModule() maybe we can make the Dock behave as the KDE
|
|
* dock, but must figure where to show the windows
|
|
* setDockWindow()
|
|
*
|
|
* Unsupported stuff (superfluous/not-essential/nonsense):
|
|
* =======================================================
|
|
*
|
|
* darkenScreen()
|
|
* setMiniIcon()
|
|
* configureWm()
|
|
* raiseSoundEvent()
|
|
* registerSoundEvent()
|
|
* unregisterSoundEvent()
|
|
* title()
|
|
* titleWithState()
|
|
* geometry() kde lib code makes it unnecessary
|
|
*
|
|
*
|
|
* Extensions to KDE:
|
|
* ==================
|
|
*
|
|
* These are clientmessage-type messages specific to Window Maker:
|
|
* wmaker:info - show info panel
|
|
* wmaker:legal - show legal panel
|
|
* wmaker:arrangeIcons - arrange icons
|
|
* wmaker:showAll - show all windows
|
|
* wmaker:hideOthers - hide others
|
|
* wmaker:restart - restart wmaker
|
|
* wmaker:exit - exit wmaker
|
|
*/
|
|
|
|
/*
|
|
* TODO
|
|
* different WORKAREA for each workspace
|
|
*/
|
|
|
|
|
|
#include "wconfig.h"
|
|
|
|
#ifdef KWM_HINTS
|
|
|
|
#include <X11/Xlib.h>
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xatom.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <signal.h>
|
|
|
|
|
|
#include "WindowMaker.h"
|
|
|
|
#include "screen.h"
|
|
#include "wcore.h"
|
|
#include "framewin.h"
|
|
#include "window.h"
|
|
#include "properties.h"
|
|
#include "icon.h"
|
|
#include "client.h"
|
|
#include "funcs.h"
|
|
#include "actions.h"
|
|
#include "workspace.h"
|
|
#include "dialog.h"
|
|
#include "stacking.h"
|
|
|
|
#include "kwm.h"
|
|
|
|
/*#define DEBUG1
|
|
*/
|
|
/******* Global ******/
|
|
|
|
extern Time LastFocusChange;
|
|
extern Time LastTimestamp;
|
|
|
|
|
|
extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
|
|
extern Atom _XA_WM_DELETE_WINDOW;
|
|
|
|
/** Local **/
|
|
|
|
static Atom _XA_KWM_COMMAND = 0;
|
|
static Atom _XA_KWM_ACTIVATE_WINDOW = 0;
|
|
static Atom _XA_KWM_ACTIVE_WINDOW = 0;
|
|
static Atom _XA_KWM_DO_NOT_MANAGE = 0;
|
|
static Atom _XA_KWM_DOCKWINDOW = 0;
|
|
static Atom _XA_KWM_RUNNING = 0;
|
|
|
|
static Atom _XA_KWM_MODULE = 0;
|
|
|
|
static Atom _XA_KWM_MODULE_INIT = 0;
|
|
static Atom _XA_KWM_MODULE_INITIALIZED = 0;
|
|
static Atom _XA_KWM_MODULE_DESKTOP_CHANGE = 0;
|
|
static Atom _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = 0;
|
|
static Atom _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = 0;
|
|
static Atom _XA_KWM_MODULE_WIN_ADD = 0;
|
|
static Atom _XA_KWM_MODULE_WIN_REMOVE = 0;
|
|
static Atom _XA_KWM_MODULE_WIN_CHANGE = 0;
|
|
static Atom _XA_KWM_MODULE_WIN_RAISE = 0;
|
|
static Atom _XA_KWM_MODULE_WIN_LOWER = 0;
|
|
static Atom _XA_KWM_MODULE_WIN_ACTIVATE = 0;
|
|
static Atom _XA_KWM_MODULE_WIN_ICON_CHANGE = 0;
|
|
static Atom _XA_KWM_MODULE_DOCKWIN_ADD = 0;
|
|
static Atom _XA_KWM_MODULE_DOCKWIN_REMOVE = 0;
|
|
|
|
static Atom _XA_KWM_WIN_UNSAVED_DATA = 0;
|
|
static Atom _XA_KWM_WIN_DECORATION = 0;
|
|
static Atom _XA_KWM_WIN_DESKTOP = 0;
|
|
static Atom _XA_KWM_WIN_GEOMETRY_RESTORE = 0;
|
|
static Atom _XA_KWM_WIN_ICONIFIED = 0;
|
|
static Atom _XA_KWM_WIN_MAXIMIZED = 0;
|
|
static Atom _XA_KWM_WIN_STICKY = 0;
|
|
|
|
static Atom _XA_KWM_WIN_ICON_GEOMETRY = 0;
|
|
|
|
static Atom _XA_KWM_CURRENT_DESKTOP = 0;
|
|
static Atom _XA_KWM_NUMBER_OF_DESKTOPS = 0;
|
|
static Atom _XA_KWM_DESKTOP_NAME_[MAX_WORKSPACES];
|
|
static Atom _XA_KWM_WINDOW_REGION_[MAX_WORKSPACES];
|
|
|
|
|
|
|
|
/* list of window titles that must not be managed */
|
|
typedef struct KWMDoNotManageList {
|
|
char title[20];
|
|
struct KWMDoNotManageList *next;
|
|
} KWMDoNotManageList;
|
|
|
|
static KWMDoNotManageList *KWMDoNotManageCrap = NULL;
|
|
|
|
|
|
/* list of KWM modules */
|
|
typedef struct KWMModuleList {
|
|
Window window;
|
|
struct KWMModuleList *next;
|
|
#ifdef DEBUG1
|
|
char *title;
|
|
#endif
|
|
} KWMModuleList;
|
|
|
|
static KWMModuleList *KWMModules = NULL;
|
|
|
|
static KWMModuleList *KWMDockWindows = NULL;
|
|
|
|
/* window decoration types */
|
|
enum {
|
|
KWMnoDecoration = 0,
|
|
KWMnormalDecoration = 1,
|
|
KWMtinyDecoration = 2,
|
|
KWMnoFocus = 256,
|
|
KWMstandaloneMenuBar = 512,
|
|
KWMdesktopIcon = 1024,
|
|
KWMstaysOnTop = 2048
|
|
};
|
|
|
|
|
|
|
|
static Bool
|
|
getSimpleHint(Window win, Atom atom, long *retval)
|
|
{
|
|
long *data = 0;
|
|
|
|
assert(atom!=0);
|
|
|
|
data = (long*)PropGetCheckProperty(win, atom, atom, 32, 1, NULL);
|
|
|
|
if (!data)
|
|
return False;
|
|
|
|
*retval = *data;
|
|
|
|
XFree(data);
|
|
|
|
return True;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
setSimpleHint(Window win, Atom atom, long value)
|
|
{
|
|
assert(atom!=0);
|
|
XChangeProperty(dpy, win, atom, atom,
|
|
32, PropModeReplace, (unsigned char*)&value, 1);
|
|
}
|
|
|
|
|
|
static void
|
|
sendClientMessage(WScreen *scr, Window window, Atom atom, long value)
|
|
{
|
|
XEvent event;
|
|
long mask = 0;
|
|
|
|
assert(atom!=0);
|
|
|
|
memset(&event, 0, sizeof(XEvent));
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.message_type = atom;
|
|
event.xclient.window = window;
|
|
event.xclient.format = 32;
|
|
event.xclient.data.l[0] = value;
|
|
event.xclient.data.l[1] = LastTimestamp;
|
|
|
|
if (scr && scr->root_win == window)
|
|
mask = SubstructureRedirectMask;
|
|
|
|
XSendEvent(dpy, window, False, mask, &event);
|
|
}
|
|
|
|
|
|
static void
|
|
sendTextMessage(WScreen *scr, Window window, Atom atom, char *text)
|
|
{
|
|
XEvent event;
|
|
long mask = 0;
|
|
int i;
|
|
|
|
assert(atom!=0);
|
|
|
|
memset(&event, 0, sizeof(XEvent));
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.message_type = atom;
|
|
event.xclient.window = window;
|
|
event.xclient.format = 8;
|
|
|
|
for (i=0; i<20 && text[i]; i++)
|
|
event.xclient.data.b[i] = text[i];
|
|
|
|
if (scr && scr->root_win == window)
|
|
mask = SubstructureRedirectMask;
|
|
|
|
XSendEvent(dpy, window, False, mask, &event);
|
|
}
|
|
|
|
|
|
static Bool
|
|
getAreaHint(Window win, Atom atom, WArea *area)
|
|
{
|
|
long *data = 0;
|
|
|
|
data = (long*)PropGetCheckProperty(win, atom, atom, 32, 4, NULL);
|
|
|
|
if (!data)
|
|
return False;
|
|
|
|
area->x1 = data[0];
|
|
area->y1 = data[1];
|
|
area->x2 = data[2] + area->x1;
|
|
area->y2 = data[3] + area->y1;
|
|
|
|
XFree(data);
|
|
|
|
return True;
|
|
}
|
|
|
|
|
|
static void
|
|
setAreaHint(Window win, Atom atom, WArea area)
|
|
{
|
|
long value[4];
|
|
|
|
assert(atom!=0);
|
|
value[0] = area.x1;
|
|
value[1] = area.y1;
|
|
value[2] = area.x2 - area.x1;
|
|
value[3] = area.y2 - area.y1;
|
|
XChangeProperty(dpy, win, atom, atom, 32, PropModeReplace,
|
|
(unsigned char*)&value, 4);
|
|
}
|
|
|
|
|
|
static void
|
|
addModule(WScreen *scr, Window window)
|
|
{
|
|
KWMModuleList *node;
|
|
long val;
|
|
WWindow *ptr;
|
|
|
|
node = malloc(sizeof(KWMModuleList));
|
|
if (!node) {
|
|
wwarning("out of memory while registering KDE module");
|
|
return;
|
|
}
|
|
|
|
node->next = KWMModules;
|
|
node->window = window;
|
|
KWMModules = node;
|
|
|
|
sendClientMessage(scr, window, _XA_KWM_MODULE_INIT, 0);
|
|
|
|
if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val==2) {
|
|
if (scr->kwm_dock != None) {
|
|
setSimpleHint(window, _XA_KWM_MODULE, 1);
|
|
} else {
|
|
KWMModuleList *ptr;
|
|
|
|
scr->kwm_dock = window;
|
|
|
|
for (ptr = KWMDockWindows; ptr!=NULL; ptr = ptr->next) {
|
|
sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
|
|
ptr->window);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* send list of windows */
|
|
for (ptr = scr->focused_window; ptr!=NULL; ptr = ptr->prev) {
|
|
if (!ptr->flags.kwm_hidden_for_modules
|
|
&& !WFLAGP(ptr, skip_window_list)) {
|
|
sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ADD,
|
|
ptr->client_win);
|
|
}
|
|
}
|
|
|
|
/* send window stacking order */
|
|
wKWMSendStacking(scr, window);
|
|
|
|
/* send focused window */
|
|
if (scr->focused_window && scr->focused_window->flags.focused) {
|
|
sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ACTIVATE,
|
|
scr->focused_window->client_win);
|
|
}
|
|
|
|
/* tell who we are */
|
|
sendTextMessage(scr, window, _XA_KWM_COMMAND, "wm:wmaker");
|
|
|
|
|
|
sendClientMessage(scr, window, _XA_KWM_MODULE_INITIALIZED, 0);
|
|
#ifdef DEBUG1
|
|
KWMModules->title = NULL;
|
|
XFetchName(dpy, window, &KWMModules->title);
|
|
printf("NEW MODULE %s\n", KWMModules->title);
|
|
#endif
|
|
}
|
|
|
|
|
|
static void
|
|
removeModule(WScreen *scr, Window window)
|
|
{
|
|
KWMModuleList *next;
|
|
|
|
if (!KWMModules) {
|
|
return;
|
|
}
|
|
|
|
if (KWMModules->window == window) {
|
|
next = KWMModules->next;
|
|
#ifdef DEBUG1
|
|
printf("REMOVING MODULE %s\n", KWMModules->title);
|
|
if (KWMModules->title)
|
|
XFree(KWMModules->title);
|
|
#endif
|
|
free(KWMModules);
|
|
KWMModules = next;
|
|
} else {
|
|
KWMModuleList *ptr;
|
|
|
|
ptr = KWMModules;
|
|
while (ptr->next) {
|
|
if (ptr->next->window == window) {
|
|
next = ptr->next->next;
|
|
#ifdef DEBUG1
|
|
printf("REMOVING MODULE %s\n", ptr->next->title);
|
|
if (ptr->next->title)
|
|
XFree(ptr->next->title);
|
|
#endif
|
|
free(ptr->next);
|
|
ptr->next->next = next;
|
|
break;
|
|
}
|
|
ptr->next = ptr->next->next;
|
|
}
|
|
}
|
|
|
|
if (scr->kwm_dock == window)
|
|
scr->kwm_dock = None;
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
addDockWindow(WScreen *scr, Window window)
|
|
{
|
|
KWMModuleList *ptr;
|
|
|
|
for (ptr = KWMDockWindows; ptr != NULL; ptr = ptr->next) {
|
|
if (ptr->window == window)
|
|
break;
|
|
}
|
|
if (!ptr) {
|
|
KWMModuleList *node;
|
|
|
|
node = malloc(sizeof(KWMModuleList));
|
|
if (!node) {
|
|
wwarning("out of memory while processing KDE dock window");
|
|
return;
|
|
}
|
|
node->next = KWMDockWindows;
|
|
KWMDockWindows = node;
|
|
node->window = window;
|
|
XSelectInput(dpy, window, StructureNotifyMask);
|
|
|
|
sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
|
|
window);
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
removeDockWindow(WScreen *scr, Window window)
|
|
{
|
|
if (!KWMDockWindows)
|
|
return;
|
|
|
|
if (KWMDockWindows->window == window) {
|
|
KWMModuleList *next;
|
|
|
|
sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_REMOVE,
|
|
window);
|
|
|
|
next = KWMDockWindows->next;
|
|
free(KWMDockWindows);
|
|
KWMDockWindows = next;
|
|
|
|
} else {
|
|
KWMModuleList *ptr, *next;
|
|
|
|
ptr = KWMDockWindows;
|
|
while (ptr->next) {
|
|
if (ptr->next->window == window) {
|
|
sendClientMessage(scr, scr->kwm_dock,
|
|
_XA_KWM_MODULE_DOCKWIN_REMOVE, window);
|
|
next = ptr->next->next;
|
|
free(ptr->next);
|
|
ptr->next = next;
|
|
return;
|
|
}
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
sendToModules(WScreen *scr, Atom atom, WWindow *wwin, long data)
|
|
{
|
|
KWMModuleList *ptr;
|
|
XEvent event;
|
|
long mask;
|
|
|
|
if (wwin) {
|
|
if (wwin->flags.kwm_hidden_for_modules
|
|
|| WFLAGP(wwin, skip_window_list))
|
|
return;
|
|
data = wwin->client_win;
|
|
}
|
|
#ifdef DEBUG1
|
|
printf("notifying %s\n",XGetAtomName(dpy, atom));
|
|
#endif
|
|
memset(&event, 0, sizeof(XEvent));
|
|
event.xclient.type = ClientMessage;
|
|
event.xclient.message_type = atom;
|
|
event.xclient.format = 32;
|
|
event.xclient.data.l[1] = LastTimestamp;
|
|
|
|
mask = 0;
|
|
if (scr && scr->root_win == data)
|
|
mask = SubstructureRedirectMask;
|
|
|
|
for (ptr = KWMModules; ptr!=NULL; ptr = ptr->next) {
|
|
event.xclient.window = ptr->window;
|
|
event.xclient.data.l[0] = data;
|
|
XSendEvent(dpy, ptr->window, False, mask, &event);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
wKWMInitStuff(WScreen *scr)
|
|
{
|
|
if (!_XA_KWM_WIN_STICKY) {
|
|
_XA_KWM_WIN_UNSAVED_DATA = XInternAtom(dpy, "KWM_WIN_UNSAVED_DATA",
|
|
False);
|
|
|
|
_XA_KWM_WIN_DECORATION = XInternAtom(dpy, "KWM_WIN_DECORATION", False);
|
|
|
|
_XA_KWM_WIN_DESKTOP = XInternAtom(dpy, "KWM_WIN_DESKTOP", False);
|
|
|
|
_XA_KWM_WIN_GEOMETRY_RESTORE = XInternAtom(dpy,
|
|
"KWM_WIN_GEOMETRY_RESTORE",
|
|
False);
|
|
|
|
_XA_KWM_WIN_STICKY = XInternAtom(dpy, "KWM_WIN_STICKY", False);
|
|
|
|
_XA_KWM_WIN_ICONIFIED = XInternAtom(dpy, "KWM_WIN_ICONIFIED", False);
|
|
|
|
_XA_KWM_WIN_MAXIMIZED = XInternAtom(dpy, "KWM_WIN_MAXIMIZED", False);
|
|
|
|
_XA_KWM_WIN_ICON_GEOMETRY = XInternAtom(dpy, "KWM_WIN_ICON_GEOMETRY",
|
|
False);
|
|
|
|
_XA_KWM_COMMAND = XInternAtom(dpy, "KWM_COMMAND", False);
|
|
|
|
_XA_KWM_ACTIVE_WINDOW = XInternAtom(dpy, "KWM_ACTIVE_WINDOW", False);
|
|
|
|
_XA_KWM_ACTIVATE_WINDOW = XInternAtom(dpy, "KWM_ACTIVATE_WINDOW",
|
|
False);
|
|
|
|
_XA_KWM_DO_NOT_MANAGE = XInternAtom(dpy, "KWM_DO_NOT_MANAGE", False);
|
|
|
|
_XA_KWM_CURRENT_DESKTOP = XInternAtom(dpy, "KWM_CURRENT_DESKTOP",
|
|
False);
|
|
|
|
_XA_KWM_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "KWM_NUMBER_OF_DESKTOPS",
|
|
False);
|
|
|
|
_XA_KWM_DOCKWINDOW = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
|
|
|
|
_XA_KWM_RUNNING = XInternAtom(dpy, "KWM_RUNNING", False);
|
|
|
|
_XA_KWM_MODULE = XInternAtom(dpy, "KWM_MODULE", False);
|
|
|
|
_XA_KWM_MODULE_INIT = XInternAtom(dpy, "KWM_MODULE_INIT", False);
|
|
_XA_KWM_MODULE_INITIALIZED = XInternAtom(dpy, "KWM_MODULE_INITIALIZED", False);
|
|
|
|
/* dunno what these do, but Matthias' patch contains it... */
|
|
_XA_KWM_MODULE_DESKTOP_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_CHANGE", False);
|
|
_XA_KWM_MODULE_DESKTOP_NAME_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NAME_CHANGE", False);
|
|
_XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NUMBER_CHANGE", False);
|
|
|
|
_XA_KWM_MODULE_WIN_ADD = XInternAtom(dpy, "KWM_MODULE_WIN_ADD", False);
|
|
_XA_KWM_MODULE_WIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_WIN_REMOVE", False);
|
|
_XA_KWM_MODULE_WIN_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_CHANGE", False);
|
|
_XA_KWM_MODULE_WIN_RAISE = XInternAtom(dpy, "KWM_MODULE_WIN_RAISE", False);
|
|
_XA_KWM_MODULE_WIN_LOWER = XInternAtom(dpy, "KWM_MODULE_WIN_LOWER", False);
|
|
_XA_KWM_MODULE_WIN_ACTIVATE = XInternAtom(dpy, "KWM_MODULE_WIN_ACTIVATE", False);
|
|
_XA_KWM_MODULE_WIN_ICON_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_ICON_CHANGE", False);
|
|
_XA_KWM_MODULE_DOCKWIN_ADD = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_ADD", False);
|
|
_XA_KWM_MODULE_DOCKWIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_REMOVE", False);
|
|
|
|
memset(_XA_KWM_WINDOW_REGION_, 0, sizeof(_XA_KWM_WINDOW_REGION_));
|
|
|
|
memset(_XA_KWM_DESKTOP_NAME_, 0, sizeof(_XA_KWM_DESKTOP_NAME_));
|
|
}
|
|
|
|
#define SETSTR(hint, str) {\
|
|
static Atom a = 0; if (!a) a = XInternAtom(dpy, #hint, False);\
|
|
XChangeProperty(dpy, scr->root_win, a, XA_STRING, 8, PropModeReplace,\
|
|
(unsigned char*)str, strlen(str));}
|
|
|
|
SETSTR(KWM_STRING_MAXIMIZE, _("Maximize"));
|
|
SETSTR(KWM_STRING_UNMAXIMIZE, _("Unmaximize"));
|
|
SETSTR(KWM_STRING_ICONIFY, _("Miniaturize"));
|
|
SETSTR(KWM_STRING_UNICONIFY, _("Deminiaturize"));
|
|
SETSTR(KWM_STRING_STICKY, _("Omnipresent"));
|
|
SETSTR(KWM_STRING_UNSTICKY, _("Not Omnipresent"));
|
|
SETSTR(KWM_STRING_STRING_MOVE, _("Move"));
|
|
SETSTR(KWM_STRING_STRING_RESIZE, _("Resize"));
|
|
SETSTR(KWM_STRING_CLOSE, _("Close"));
|
|
SETSTR(KWM_STRING_TODESKTOP, _("Move To"));
|
|
SETSTR(KWM_STRING_ONTOCURRENTDESKTOP, _("Bring Here"));
|
|
#undef SETSTR
|
|
}
|
|
|
|
|
|
void
|
|
wKWMSendStacking(WScreen *scr, Window module)
|
|
{
|
|
int i;
|
|
WCoreWindow *core;
|
|
|
|
for (i = 0; i < MAX_WINDOW_LEVELS; i++) {
|
|
for (core = scr->stacking_list[i]; core != NULL;
|
|
core = core->stacking->under) {
|
|
WWindow *wwin;
|
|
|
|
wwin = wWindowFor(core->window);
|
|
if (wwin)
|
|
sendClientMessage(scr, module, _XA_KWM_MODULE_WIN_RAISE,
|
|
wwin->client_win);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
wKWMBroadcastStacking(WScreen *scr)
|
|
{
|
|
KWMModuleList *ptr = KWMModules;
|
|
|
|
while (ptr) {
|
|
wKWMSendStacking(scr, ptr->window);
|
|
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
|
|
|
|
char*
|
|
wKWMGetWorkspaceName(WScreen *scr, int workspace)
|
|
{
|
|
Atom type_ret;
|
|
int fmt_ret;
|
|
unsigned long nitems_ret;
|
|
unsigned long bytes_after_ret;
|
|
char *data = NULL, *tmp;
|
|
char buffer[64];
|
|
|
|
assert(workspace >= 0 && workspace < MAX_WORKSPACES);
|
|
|
|
if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
|
|
sprintf(buffer, "KWM_DESKTOP_NAME_%d", workspace + 1);
|
|
|
|
_XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
|
|
}
|
|
|
|
/* What do these people have against correctly using property types? */
|
|
if (XGetWindowProperty(dpy, scr->root_win,
|
|
_XA_KWM_DESKTOP_NAME_[workspace], 0, 128, False,
|
|
XA_STRING,
|
|
&type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
|
|
(unsigned char**)&data)!=Success || !data)
|
|
return NULL;
|
|
|
|
tmp = wstrdup(data);
|
|
XFree(data);
|
|
|
|
return tmp;
|
|
}
|
|
|
|
|
|
void
|
|
wKWMSetInitializedHint(WScreen *scr)
|
|
{
|
|
setSimpleHint(scr->root_win, _XA_KWM_RUNNING, 1);
|
|
}
|
|
|
|
|
|
void
|
|
wKWMShutdown(WScreen *scr, Bool closeModules)
|
|
{
|
|
KWMModuleList *ptr;
|
|
|
|
XDeleteProperty(dpy, scr->root_win, _XA_KWM_RUNNING);
|
|
|
|
if (closeModules) {
|
|
for (ptr = KWMModules; ptr != NULL; ptr = ptr->next) {
|
|
XKillClient(dpy, ptr->window);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
wKWMCheckClientHints(WWindow *wwin, int *layer, int *workspace)
|
|
{
|
|
long val;
|
|
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA, &val)
|
|
&& val) {
|
|
|
|
wwin->client_flags.broken_close = 1;
|
|
}
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &val)) {
|
|
if (val & KWMnoFocus) {
|
|
wwin->client_flags.no_focusable = 1;
|
|
}
|
|
switch (val & ~KWMnoFocus) {
|
|
case KWMnoDecoration:
|
|
wwin->client_flags.no_titlebar = 1;
|
|
wwin->client_flags.no_resizebar = 1;
|
|
break;
|
|
case KWMtinyDecoration:
|
|
wwin->client_flags.no_resizebar = 1;
|
|
break;
|
|
case KWMstandaloneMenuBar:
|
|
wwin->client_flags.no_titlebar = 1;
|
|
wwin->client_flags.no_resizebar = 1;
|
|
wwin->client_flags.no_resizable = 1;
|
|
wwin->client_flags.skip_window_list = 1;
|
|
wwin->client_flags.no_hide_others = 1;
|
|
wwin->flags.kwm_menubar = 1;
|
|
*layer = WMMainMenuLevel;
|
|
break;
|
|
case KWMdesktopIcon:
|
|
*layer = WMDesktopLevel;
|
|
break;
|
|
case KWMstaysOnTop:
|
|
*layer = WMFloatingLevel;
|
|
break;
|
|
case KWMnormalDecoration:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &val)) {
|
|
*workspace = val - 1;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
wKWMCheckClientInitialState(WWindow *wwin)
|
|
{
|
|
long val;
|
|
WArea area;
|
|
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, &val) && val) {
|
|
|
|
wwin->client_flags.omnipresent = 1;
|
|
}
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED, &val) && val) {
|
|
|
|
wwin->flags.miniaturized = 1;
|
|
}
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &val) && val) {
|
|
|
|
wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
|
|
}
|
|
if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
|
|
&& (wwin->old_geometry.x != area.x1
|
|
|| wwin->old_geometry.y != area.y1
|
|
|| wwin->old_geometry.width != area.x2 - area.x1
|
|
|| wwin->old_geometry.height != area.y2 - area.y1)) {
|
|
|
|
wwin->old_geometry.x = area.x1;
|
|
wwin->old_geometry.y = area.y1;
|
|
wwin->old_geometry.width = area.x2 - area.x1;
|
|
wwin->old_geometry.height = area.y2 - area.y1;
|
|
}
|
|
}
|
|
|
|
|
|
Bool
|
|
wKWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event)
|
|
{
|
|
Bool processed = True;
|
|
Bool flag;
|
|
long value;
|
|
|
|
|
|
if (!wwin->frame) {
|
|
return False;
|
|
}
|
|
|
|
if (event->atom == _XA_KWM_WIN_UNSAVED_DATA) {
|
|
#ifdef DEBUG1
|
|
printf("got KDE unsaved data change\n");
|
|
#endif
|
|
|
|
flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA,
|
|
&value) && value;
|
|
|
|
if (flag != wwin->client_flags.broken_close) {
|
|
wwin->client_flags.broken_close = flag;
|
|
if (wwin->frame)
|
|
wWindowUpdateButtonImages(wwin);
|
|
}
|
|
} else if (event->atom == _XA_KWM_WIN_STICKY) {
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE sticky change\n");
|
|
#endif
|
|
flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
|
|
&value) || value;
|
|
|
|
if (flag != wwin->client_flags.omnipresent) {
|
|
|
|
wwin->client_flags.omnipresent = flag;
|
|
|
|
UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
|
|
|
|
}
|
|
} else if (event->atom == _XA_KWM_WIN_MAXIMIZED) {
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE maximize change\n");
|
|
#endif
|
|
flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED,
|
|
&value) || value;
|
|
|
|
if (flag != (wwin->flags.maximized!=0)) {
|
|
|
|
if (flag)
|
|
wMaximizeWindow(wwin, flag*(MAX_VERTICAL|MAX_HORIZONTAL));
|
|
else
|
|
wUnmaximizeWindow(wwin);
|
|
}
|
|
} else if (event->atom == _XA_KWM_WIN_ICONIFIED) {
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE iconify change\n");
|
|
#endif
|
|
flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
|
|
&value) || value;
|
|
|
|
if (flag != wwin->flags.miniaturized) {
|
|
|
|
if (flag)
|
|
wIconifyWindow(wwin);
|
|
else
|
|
wDeiconifyWindow(wwin);
|
|
}
|
|
|
|
} else if (event->atom == _XA_KWM_WIN_DECORATION) {
|
|
Bool refresh = False;
|
|
int oldnofocus;
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE decoration change\n");
|
|
#endif
|
|
|
|
oldnofocus = wwin->client_flags.no_focusable;
|
|
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &value)) {
|
|
wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
|
|
|
|
switch (value & ~KWMnoFocus) {
|
|
case KWMnoDecoration:
|
|
if (!WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
|
|
refresh = True;
|
|
|
|
wwin->client_flags.no_titlebar = 1;
|
|
wwin->client_flags.no_resizebar = 1;
|
|
break;
|
|
|
|
case KWMtinyDecoration:
|
|
if (WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
|
|
refresh = True;
|
|
|
|
wwin->client_flags.no_titlebar = 0;
|
|
wwin->client_flags.no_resizebar = 1;
|
|
break;
|
|
|
|
case KWMnormalDecoration:
|
|
default:
|
|
if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
|
|
refresh = True;
|
|
|
|
wwin->client_flags.no_titlebar = 0;
|
|
wwin->client_flags.no_resizebar = 0;
|
|
break;
|
|
}
|
|
} else {
|
|
if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
|
|
refresh = True;
|
|
wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
|
|
wwin->client_flags.no_titlebar = 0;
|
|
wwin->client_flags.no_resizebar = 0;
|
|
}
|
|
|
|
if (refresh)
|
|
wWindowConfigureBorders(wwin);
|
|
|
|
if (wwin->client_flags.no_focusable && !oldnofocus) {
|
|
|
|
sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_REMOVE,
|
|
wwin, 0);
|
|
wwin->flags.kwm_hidden_for_modules = 1;
|
|
|
|
} else if (!wwin->client_flags.no_focusable && oldnofocus) {
|
|
|
|
if (wwin->flags.kwm_hidden_for_modules) {
|
|
sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_ADD,
|
|
wwin, 0);
|
|
wwin->flags.kwm_hidden_for_modules = 0;
|
|
}
|
|
}
|
|
} else if (event->atom == _XA_KWM_WIN_DESKTOP && wwin->frame) {
|
|
#ifdef DEBUG1
|
|
printf("got KDE workspace change for %s\n", wwin->frame->title);
|
|
#endif
|
|
if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &value)
|
|
&& value-1 != wwin->frame->workspace) {
|
|
wWindowChangeWorkspace(wwin, value-1);
|
|
}
|
|
|
|
} else if (event->atom == _XA_KWM_WIN_GEOMETRY_RESTORE) {
|
|
WArea area;
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE geometry restore change\n");
|
|
#endif
|
|
if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
|
|
&& (wwin->old_geometry.x != area.x1
|
|
|| wwin->old_geometry.y != area.y1
|
|
|| wwin->old_geometry.width != area.x2 - area.x1
|
|
|| wwin->old_geometry.height != area.y2 - area.y1)) {
|
|
|
|
wwin->old_geometry.x = area.x1;
|
|
wwin->old_geometry.y = area.y1;
|
|
wwin->old_geometry.width = area.x2 - area.x1;
|
|
wwin->old_geometry.height = area.y2 - area.y1;
|
|
}
|
|
} else {
|
|
processed = False;
|
|
}
|
|
|
|
return processed;
|
|
}
|
|
|
|
|
|
static Bool
|
|
performWindowCommand(WScreen *scr, char *command)
|
|
{
|
|
WWindow *wwin = NULL;
|
|
|
|
|
|
wwin = scr->focused_window;
|
|
if (!wwin || !wwin->flags.focused || !wwin->flags.mapped) {
|
|
wwin = NULL;
|
|
}
|
|
|
|
CloseWindowMenu(scr);
|
|
|
|
|
|
if (strcmp(command, "winMove")==0 || strcmp(command, "winResize")==0) {
|
|
|
|
if (wwin)
|
|
wKeyboardMoveResizeWindow(wwin);
|
|
|
|
} else if (strcmp(command, "winMaximize")==0) {
|
|
|
|
if (wwin)
|
|
wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
|
|
|
|
} else if (strcmp(command, "winRestore")==0) {
|
|
|
|
if (wwin && wwin->flags.maximized)
|
|
wUnmaximizeWindow(wwin);
|
|
|
|
} else if (strcmp(command, "winIconify")==0) {
|
|
|
|
|
|
if (wwin && !WFLAGP(wwin, no_miniaturizable)) {
|
|
if (wwin->protocols.MINIATURIZE_WINDOW)
|
|
wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
|
|
LastTimestamp);
|
|
else {
|
|
wIconifyWindow(wwin);
|
|
}
|
|
}
|
|
|
|
} else if (strcmp(command, "winClose")==0) {
|
|
|
|
if (wwin && !WFLAGP(wwin, no_closable)) {
|
|
if (wwin->protocols.DELETE_WINDOW)
|
|
wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
|
|
}
|
|
|
|
} else if (strcmp(command, "winSticky")==0) {
|
|
|
|
if (wwin) {
|
|
wwin->client_flags.omnipresent ^= 1;
|
|
UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
|
|
}
|
|
|
|
} else if (strcmp(command, "winShade")==0) {
|
|
|
|
if (wwin && !WFLAGP(wwin, no_shadeable)) {
|
|
if (wwin->flags.shaded)
|
|
wUnshadeWindow(wwin);
|
|
else
|
|
wShadeWindow(wwin);
|
|
}
|
|
|
|
} else if (strcmp(command, "winOperation")==0) {
|
|
|
|
if (wwin)
|
|
OpenWindowMenu(wwin, wwin->frame_x,
|
|
wwin->frame_y+wwin->frame->top_width, True);
|
|
|
|
} else {
|
|
return False;
|
|
}
|
|
|
|
return True;
|
|
}
|
|
|
|
|
|
static void
|
|
performCommand(WScreen *scr, char *command, XClientMessageEvent *event)
|
|
{
|
|
assert(scr != NULL);
|
|
|
|
if (strcmp(command, "commandLine")==0
|
|
|| strcmp(command, "execute")==0) {
|
|
char *cmd;
|
|
|
|
cmd = ExpandOptions(scr, _("%a(Run Command,Type the command to run:)"));
|
|
if (cmd) {
|
|
ExecuteShellCommand(scr, cmd);
|
|
free(cmd);
|
|
}
|
|
} else if (strcmp(command, "logout")==0) {
|
|
|
|
Shutdown(WSLogoutMode);
|
|
|
|
} else if (strcmp(command, "refreshScreen")==0) {
|
|
|
|
wRefreshDesktop(scr);
|
|
|
|
} else if (strncmp(command, "go:", 3)==0) {
|
|
|
|
Shutdown(WSRestartPreparationMode);
|
|
Restart(&command[3], False);
|
|
Restart(NULL, True);
|
|
|
|
} else if (strcmp(command, "desktop+1")==0) {
|
|
|
|
wWorkspaceRelativeChange(scr, 1);
|
|
|
|
} else if (strcmp(command, "desktop-1")==0) {
|
|
|
|
wWorkspaceRelativeChange(scr, -1);
|
|
|
|
} else if (strcmp(command, "desktop+2")==0) {
|
|
|
|
wWorkspaceRelativeChange(scr, 2);
|
|
|
|
} else if (strcmp(command, "desktop-2")==0) {
|
|
|
|
wWorkspaceRelativeChange(scr, -2);
|
|
|
|
} else if (strcmp(command, "desktop%%2")==0) {
|
|
|
|
if (scr->current_workspace % 2 == 1)
|
|
wWorkspaceRelativeChange(scr, 1);
|
|
else
|
|
wWorkspaceRelativeChange(scr, -1);
|
|
} else if (strncmp(command, "desktop", 7)==0) {
|
|
int ws;
|
|
|
|
ws = atoi(&command[7]);
|
|
wWorkspaceChange(scr, ws);
|
|
|
|
/* wmaker specific stuff */
|
|
} else if (strcmp(command, "wmaker:info")==0) {
|
|
|
|
wShowInfoPanel(scr);
|
|
|
|
} else if (strcmp(command, "wmaker:legal")==0) {
|
|
|
|
wShowLegalPanel(scr);
|
|
|
|
} else if (strcmp(command, "wmaker:arrangeIcons")==0) {
|
|
|
|
wArrangeIcons(scr, True);
|
|
|
|
} else if (strcmp(command, "wmaker:showAll")==0) {
|
|
|
|
wShowAllWindows(scr);
|
|
|
|
} else if (strcmp(command, "wmaker:hideOthers")==0) {
|
|
|
|
wHideOtherApplications(scr->focused_window);
|
|
|
|
} else if (strcmp(command, "wmaker:restart")==0) {
|
|
|
|
Shutdown(WSRestartPreparationMode);
|
|
Restart(NULL, True);
|
|
|
|
} else if (strcmp(command, "wmaker:exit")==0) {
|
|
|
|
Shutdown(WSExitMode);
|
|
|
|
#ifdef UNSUPPORTED_STUFF
|
|
} else if (strcmp(command, "moduleRaised")==0) { /* useless */
|
|
} else if (strcmp(command, "deskUnclutter")==0) {
|
|
} else if (strcmp(command, "deskCascade")==0) {
|
|
} else if (strcmp(command, "configure")==0) {
|
|
} else if (strcmp(command, "taskManager")==0) {
|
|
} else if (strcmp(command, "darkenScreen")==0) { /* breaks consistency */
|
|
#endif
|
|
} else if (!performWindowCommand(scr, command)) {
|
|
KWMModuleList *module;
|
|
long mask = 0;
|
|
XEvent ev;
|
|
/* do message relay thing */
|
|
|
|
ev.xclient = *event;
|
|
for (module = KWMModules; module != NULL; module = module->next) {
|
|
|
|
ev.xclient.window = module->window;
|
|
if (module->window == scr->root_win)
|
|
mask = SubstructureRedirectMask;
|
|
else
|
|
mask = 0;
|
|
|
|
XSendEvent(dpy, module->window, False, mask, &ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Bool
|
|
wKWMProcessClientMessage(XClientMessageEvent *event)
|
|
{
|
|
Bool processed = True;
|
|
WScreen *scr;
|
|
#ifdef DEBUG1
|
|
printf("CLIENT MESS %s\n", XGetAtomName(dpy, event->message_type));
|
|
#endif
|
|
if (event->message_type == _XA_KWM_COMMAND && event->format==8) {
|
|
char buffer[24];
|
|
int i;
|
|
|
|
scr = wScreenForRootWindow(event->window);
|
|
|
|
for (i=0; i<20; i++) {
|
|
buffer[i] = event->data.b[i];
|
|
}
|
|
buffer[i] = 0;
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE command %s\n", buffer);
|
|
#endif
|
|
performCommand(scr, buffer, event);
|
|
|
|
} else if (event->message_type == _XA_KWM_ACTIVATE_WINDOW) {
|
|
WWindow *wwin;
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE activate internal\n");
|
|
#endif
|
|
wwin = wWindowFor(event->data.l[0]);
|
|
|
|
if (wwin)
|
|
wSetFocusTo(wwin->screen_ptr, wwin);
|
|
|
|
} else if (event->message_type == _XA_KWM_DO_NOT_MANAGE
|
|
&& event->format == 8) {
|
|
KWMDoNotManageList *node;
|
|
int i;
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE dont manage\n");
|
|
#endif
|
|
|
|
node = malloc(sizeof(KWMDoNotManageList));
|
|
if (!node) {
|
|
wwarning("out of memory processing KWM_DO_NOT_MANAGE message");
|
|
}
|
|
for (i=0; i<20 && event->data.b[i]; i++)
|
|
node->title[i] = event->data.b[i];
|
|
node->title[i] = 0;
|
|
|
|
node->next = KWMDoNotManageCrap;
|
|
KWMDoNotManageCrap = node;
|
|
|
|
} else if (event->message_type == _XA_KWM_MODULE) {
|
|
long val;
|
|
Window modwin = event->data.l[0];
|
|
|
|
scr = wScreenForRootWindow(event->window);
|
|
|
|
if (getSimpleHint(modwin, _XA_KWM_MODULE, &val) && val) {
|
|
#ifdef DEBUG1
|
|
puts("got KDE module startup");
|
|
#endif
|
|
addModule(scr, modwin);
|
|
} else {
|
|
#ifdef DEBUG1
|
|
puts("got KDE module finish");
|
|
#endif
|
|
removeModule(scr, modwin);
|
|
}
|
|
} else {
|
|
processed = False;
|
|
}
|
|
|
|
return processed;
|
|
}
|
|
|
|
|
|
void
|
|
wKWMCheckModule(WScreen *scr, Window window)
|
|
{
|
|
long val;
|
|
|
|
if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val) {
|
|
#ifdef DEBUG1
|
|
puts("got KDE module startup");
|
|
#endif
|
|
addModule(scr, window);
|
|
}
|
|
}
|
|
|
|
|
|
Bool
|
|
wKWMCheckRootHintChange(WScreen *scr, XPropertyEvent *event)
|
|
{
|
|
Bool processed = True;
|
|
long value;
|
|
|
|
if (event->atom == _XA_KWM_CURRENT_DESKTOP) {
|
|
if (getSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP, &value)) {
|
|
#ifdef DEBUG1
|
|
printf("got KDE workspace switch to %li\n", value);
|
|
#endif
|
|
if (value-1 != scr->current_workspace) {
|
|
wWorkspaceChange(scr, value-1);
|
|
}
|
|
}
|
|
} else if (event->atom == _XA_KWM_NUMBER_OF_DESKTOPS) {
|
|
#ifdef DEBUG1
|
|
printf("got KDE workspace number change\n");
|
|
#endif
|
|
|
|
if (getSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS, &value)) {
|
|
|
|
/* increasing is easy... */
|
|
if (value > scr->workspace_count) {
|
|
scr->flags.kwm_syncing_count = 1;
|
|
|
|
wWorkspaceMake(scr, value - scr->workspace_count);
|
|
|
|
scr->flags.kwm_syncing_count = 0;
|
|
|
|
} else if (value < scr->workspace_count) {
|
|
int i;
|
|
Bool rebuild = False;
|
|
|
|
scr->flags.kwm_syncing_count = 1;
|
|
|
|
/* decrease all we can do */
|
|
for (i = scr->workspace_count; i >= value; i--) {
|
|
if (!wWorkspaceDelete(scr, i)) {
|
|
rebuild = True;
|
|
break;
|
|
}
|
|
}
|
|
|
|
scr->flags.kwm_syncing_count = 0;
|
|
|
|
/* someone destroyed a workspace that can't be destroyed.
|
|
* Reset the hints to reflect our internal state.
|
|
*/
|
|
if (rebuild) {
|
|
wKWMUpdateWorkspaceCountHint(scr);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
int i;
|
|
|
|
processed = False;
|
|
|
|
for (i = 0; i < MAX_WORKSPACES && i < scr->workspace_count; i++) {
|
|
if (event->atom == _XA_KWM_DESKTOP_NAME_[i]) {
|
|
char *name;
|
|
|
|
name = wKWMGetWorkspaceName(scr, i);
|
|
|
|
#ifdef DEBUG1
|
|
printf("got KDE workspace name change to %s\n", name);
|
|
#endif
|
|
|
|
if (name && strncmp(name, scr->workspaces[i]->name,
|
|
MAX_WORKSPACENAME_WIDTH)!=0) {
|
|
scr->flags.kwm_syncing_name = 1;
|
|
wWorkspaceRename(scr, i, name);
|
|
scr->flags.kwm_syncing_name = 0;
|
|
}
|
|
if (name)
|
|
XFree(name);
|
|
processed = True;
|
|
break;
|
|
} else if (event->atom == _XA_KWM_WINDOW_REGION_[i]) {
|
|
WArea area;
|
|
|
|
if (getAreaHint(scr->root_win, event->atom, &area)) {
|
|
|
|
if (scr->totalUsableArea.x1 != area.x1
|
|
|| scr->totalUsableArea.y1 != area.y1
|
|
|| scr->totalUsableArea.x2 != area.x2
|
|
|| scr->totalUsableArea.y2 != area.y2) {
|
|
wScreenUpdateUsableArea(scr);
|
|
}
|
|
}
|
|
|
|
processed = True;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return processed;
|
|
}
|
|
|
|
|
|
Bool
|
|
wKWMManageableClient(WScreen *scr, Window win, char *title)
|
|
{
|
|
KWMDoNotManageList *ptr, *next;
|
|
long val;
|
|
|
|
if (getSimpleHint(win, _XA_KWM_DOCKWINDOW, &val) && val) {
|
|
addDockWindow(scr, win);
|
|
return False;
|
|
}
|
|
|
|
ptr = KWMDoNotManageCrap;
|
|
/*
|
|
* TODO: support for glob patterns or regexes
|
|
*/
|
|
if (ptr && strncmp(ptr->title, title, strlen(ptr->title))==0) {
|
|
next = ptr->next;
|
|
free(ptr);
|
|
KWMDoNotManageCrap = next;
|
|
#ifdef DEBUG1
|
|
printf("window %s not managed per KDE request\n", title);
|
|
#endif
|
|
|
|
sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
|
|
sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
|
|
|
|
return False;
|
|
} else if (ptr) {
|
|
while (ptr->next) {
|
|
if (strncmp(ptr->next->title, title, strlen(ptr->next->title))==0) {
|
|
#ifdef DEBUG1
|
|
printf("window %s not managed per KDE request\n", title);
|
|
#endif
|
|
next = ptr->next->next;
|
|
free(ptr->next);
|
|
ptr->next = next;
|
|
|
|
sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
|
|
sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
|
|
|
|
return False;
|
|
}
|
|
|
|
ptr = ptr->next;
|
|
}
|
|
}
|
|
|
|
return True;
|
|
}
|
|
|
|
|
|
void
|
|
wKWMUpdateCurrentWorkspaceHint(WScreen *scr)
|
|
{
|
|
setSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP,
|
|
scr->current_workspace+1);
|
|
|
|
sendToModules(scr, _XA_KWM_MODULE_DESKTOP_CHANGE, NULL,
|
|
scr->current_workspace+1);
|
|
}
|
|
|
|
|
|
void
|
|
wKWMUpdateActiveWindowHint(WScreen *scr)
|
|
{
|
|
long val;
|
|
WWindow *wwin, *tmp;
|
|
|
|
if (!scr->focused_window || !scr->focused_window->flags.focused)
|
|
val = None;
|
|
else {
|
|
val = (long)(scr->focused_window->client_win);
|
|
|
|
/* raise the menubar thing */
|
|
wwin = scr->focused_window;
|
|
tmp = wwin->prev;
|
|
while (tmp) {
|
|
if (tmp->flags.kwm_menubar
|
|
&& tmp->transient_for == wwin->client_win) {
|
|
wRaiseFrame(tmp->frame->core);
|
|
break;
|
|
}
|
|
tmp = tmp->prev;
|
|
}
|
|
}
|
|
|
|
XChangeProperty(dpy, scr->root_win, _XA_KWM_ACTIVE_WINDOW,
|
|
_XA_KWM_ACTIVE_WINDOW, 32, PropModeReplace,
|
|
(unsigned char*)&val, 1);
|
|
XFlush(dpy);
|
|
}
|
|
|
|
|
|
void
|
|
wKWMUpdateWorkspaceCountHint(WScreen *scr)
|
|
{
|
|
if (scr->flags.kwm_syncing_count)
|
|
return;
|
|
|
|
setSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS,
|
|
scr->workspace_count);
|
|
|
|
sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE, NULL,
|
|
scr->workspace_count);
|
|
}
|
|
|
|
|
|
void
|
|
wKWMCheckDestroy(XDestroyWindowEvent *event)
|
|
{
|
|
WScreen *scr;
|
|
|
|
if (event->event == event->window) {
|
|
return;
|
|
}
|
|
|
|
scr = wScreenSearchForRootWindow(event->event);
|
|
if (!scr) {
|
|
return;
|
|
}
|
|
|
|
removeModule(scr, event->window);
|
|
removeDockWindow(scr, event->window);
|
|
}
|
|
|
|
|
|
void
|
|
wKWMUpdateWorkspaceNameHint(WScreen *scr, int workspace)
|
|
{
|
|
char buffer[64];
|
|
|
|
assert(workspace >= 0 && workspace < MAX_WORKSPACES);
|
|
|
|
if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
|
|
sprintf(buffer, "KWM_DESKTOP_NAME_%d", workspace + 1);
|
|
|
|
_XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
|
|
}
|
|
|
|
XChangeProperty(dpy, scr->root_win, _XA_KWM_DESKTOP_NAME_[workspace],
|
|
XA_STRING, 8, PropModeReplace,
|
|
(unsigned char*)scr->workspaces[workspace]->name,
|
|
strlen(scr->workspaces[workspace]->name)+1);
|
|
|
|
sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NAME_CHANGE, NULL, workspace+1);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
wKWMUpdateClientWorkspace(WWindow *wwin)
|
|
{
|
|
#ifdef DEBUG1
|
|
printf("updating workspace of %s to %i\n",
|
|
wwin->frame->title, wwin->frame->workspace+1);
|
|
#endif
|
|
setSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP,
|
|
wwin->frame->workspace+1);
|
|
}
|
|
|
|
|
|
void
|
|
wKWMUpdateClientGeometryRestore(WWindow *wwin)
|
|
{
|
|
WArea rect;
|
|
|
|
rect.x1 = wwin->old_geometry.x;
|
|
rect.y1 = wwin->old_geometry.y;
|
|
rect.x2 = wwin->old_geometry.x + wwin->old_geometry.width;
|
|
rect.y2 = wwin->old_geometry.y + wwin->old_geometry.height;
|
|
|
|
setAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, rect);
|
|
}
|
|
|
|
|
|
void
|
|
wKWMUpdateClientStateHint(WWindow *wwin, WKWMStateFlag flags)
|
|
{
|
|
if (flags & KWMIconifiedFlag) {
|
|
setSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
|
|
wwin->flags.miniaturized /*|| wwin->flags.shaded
|
|
|| wwin->flags.hidden*/);
|
|
}
|
|
if (flags & KWMStickyFlag) {
|
|
setSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY,
|
|
IS_OMNIPRESENT(wwin));
|
|
}
|
|
if (flags & KWMMaximizedFlag) {
|
|
setSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED,
|
|
wwin->flags.maximized!=0);
|
|
}
|
|
}
|
|
|
|
|
|
Bool
|
|
wKWMGetUsableArea(WScreen *scr, WArea *area)
|
|
{
|
|
char buffer[64];
|
|
|
|
if (_XA_KWM_WINDOW_REGION_[0]==0) {
|
|
sprintf(buffer, "KWM_WINDOW_REGION_%d", 1);
|
|
|
|
_XA_KWM_WINDOW_REGION_[0] = XInternAtom(dpy, buffer, False);
|
|
}
|
|
|
|
return getAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[0], area);
|
|
}
|
|
|
|
|
|
|
|
Bool
|
|
wKWMGetIconGeometry(WWindow *wwin, WArea *area)
|
|
{
|
|
return getAreaHint(wwin->client_win, _XA_KWM_WIN_ICON_GEOMETRY, area);
|
|
}
|
|
|
|
|
|
|
|
#ifdef not_used
|
|
void
|
|
wKWMSetUsableAreaHint(WScreen *scr, int workspace)
|
|
{
|
|
/* if we set this after making changes of our own to the area,
|
|
* the next time the area changes, we won't know what should
|
|
* be the new final area. This protocol isn't worth a shit :/
|
|
*/
|
|
/*
|
|
* According to Matthias Ettrich:
|
|
* Indeed, there's no protocol to deal with the area yet in case several
|
|
* clients want to influence it. It is sufficent, though, if it is clear
|
|
* that one process is responsable for the area. For KDE this is kpanel, but
|
|
* I see that there might be a conflict with the docking area of windowmaker
|
|
* itself.
|
|
*
|
|
*/
|
|
|
|
#ifdef notdef
|
|
char buffer[64];
|
|
|
|
assert(workspace >= 0 && workspace < MAX_WORKSPACES);
|
|
|
|
if (_XA_KWM_WINDOW_REGION_[workspace]==0) {
|
|
sprintf(buffer, "KWM_WINDOW_REGION_%d", workspace+1);
|
|
|
|
_XA_KWM_WINDOW_REGION_[workspace] = XInternAtom(dpy, buffer, False);
|
|
}
|
|
|
|
setAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[workspace],
|
|
scr->totalUsableArea);
|
|
#endif
|
|
}
|
|
#endif /* not_used */
|
|
|
|
void
|
|
wKWMSendEventMessage(WWindow *wwin, WKWMEventMessage message)
|
|
{
|
|
Atom msg;
|
|
|
|
if (wwin && (wwin->flags.internal_window
|
|
|| wwin->flags.kwm_hidden_for_modules
|
|
|| !wwin->flags.kwm_managed
|
|
|| WFLAGP(wwin, skip_window_list)))
|
|
return;
|
|
|
|
switch (message) {
|
|
case WKWMAddWindow:
|
|
msg = _XA_KWM_MODULE_WIN_ADD;
|
|
break;
|
|
case WKWMRemoveWindow:
|
|
msg = _XA_KWM_MODULE_WIN_REMOVE;
|
|
break;
|
|
case WKWMFocusWindow:
|
|
msg = _XA_KWM_MODULE_WIN_ACTIVATE;
|
|
break;
|
|
case WKWMRaiseWindow:
|
|
msg = _XA_KWM_MODULE_WIN_RAISE;
|
|
break;
|
|
case WKWMLowerWindow:
|
|
msg = _XA_KWM_MODULE_WIN_LOWER;
|
|
break;
|
|
case WKWMChangedClient:
|
|
msg = _XA_KWM_MODULE_WIN_CHANGE;
|
|
break;
|
|
case WKWMIconChange:
|
|
msg = _XA_KWM_MODULE_WIN_ICON_CHANGE;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
sendToModules(wwin ? wwin->screen_ptr : NULL, msg, wwin, 0);
|
|
}
|
|
|
|
|
|
static void
|
|
writeSocket(int sock, char *data)
|
|
{
|
|
char buffer[128];
|
|
|
|
sprintf(buffer, "%i ", strlen(data));
|
|
write(sock, buffer, strlen(buffer));
|
|
write(sock, data, strlen(data));
|
|
}
|
|
|
|
|
|
static int
|
|
connectKFM(WScreen *scr)
|
|
{
|
|
char *path;
|
|
char buffer[128];
|
|
char *ptr;
|
|
FILE *f;
|
|
int pid;
|
|
int sock = 0;
|
|
struct sockaddr_un addr;
|
|
|
|
path = wstrappend(wgethomedir(), "/.kde/share/apps/kfm/pid");
|
|
strcpy(buffer, getenv("DISPLAY"));
|
|
|
|
ptr = strchr(buffer, ':');
|
|
if (ptr)
|
|
*ptr = '_';
|
|
|
|
ptr = strrchr(buffer, '.');
|
|
if (ptr)
|
|
*ptr = 0;
|
|
{
|
|
char b[32];
|
|
|
|
sprintf(b, ".%i", scr->screen);
|
|
strcat(buffer, b);
|
|
}
|
|
ptr = path;
|
|
path = wstrappend(ptr, buffer);
|
|
free(ptr);
|
|
|
|
/* pid file */
|
|
f = fopen(path, "r");
|
|
free(path);
|
|
if (!f)
|
|
return -1;
|
|
|
|
buffer[0] = 0;
|
|
fgets(buffer, 123, f);
|
|
pid = atoi(buffer);
|
|
if (pid <= 0)
|
|
return -1;
|
|
|
|
if (kill(pid, 0) != 0)
|
|
return -1;
|
|
|
|
buffer[0] = 0;
|
|
fscanf(f, "%s", buffer);
|
|
fclose(f);
|
|
|
|
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (sock < 0)
|
|
return -1;
|
|
addr.sun_family = AF_UNIX;
|
|
strcpy(addr.sun_path, buffer);
|
|
|
|
if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
|
close(sock);
|
|
return -1;
|
|
}
|
|
|
|
path = wstrappend(wgethomedir(), "/.kde/share/apps/kfm/magic");
|
|
f = fopen(path, "r");
|
|
if (!f) {
|
|
return -1;
|
|
}
|
|
ptr = fgets(buffer, 123, f);
|
|
fclose(f);
|
|
if (!ptr) {
|
|
return -1;
|
|
}
|
|
puts(buffer);
|
|
|
|
ptr = wstrappend("auth", buffer);
|
|
|
|
writeSocket(sock, ptr);
|
|
free(ptr);
|
|
|
|
return sock;
|
|
}
|
|
|
|
|
|
void
|
|
wKWMSelectRootRegion(WScreen *scr, int x, int y, int w, int h, Bool control)
|
|
{
|
|
#if 0
|
|
char buffer[128];
|
|
int sock;
|
|
|
|
puts("CONNECTING");
|
|
sock = connectKFM(scr);
|
|
if (sock < 0)
|
|
return;
|
|
puts("SENDING DATA");
|
|
|
|
sprintf(buffer, "selectRootIcons %i %i %i %i %c", x, y, w, h, control);
|
|
writeSocket(sock, buffer);
|
|
|
|
close(sock);
|
|
#endif
|
|
}
|
|
|
|
|
|
#endif /* KWM_HINTS */
|