📄 wm_state.c
字号:
// We have to be unmapped to change motif decoration hints withdraw_window(dpy, win); remove_motif_decorations(dpy, win); XSetWMNormalHints(dpy, win, sizehints); XFree(sizehints); XMapWindow(dpy, win); /* wait for the window to be mapped */ do { XNextEvent(dpy, &ev); } while(ev.type != MapNotify); /* remove any outstanding configure_notifies */ XSync(dpy, True); // Try to resize, place the window at correct place and on top XGetWindowAttributes(dpy, win, &attrs); DpyInfoGetScreenOffset(dpy, XScreenNumberOfScreen(attrs.screen), &win_changes.x, &win_changes.y); DpyInfoGetResolution(dpy, XScreenNumberOfScreen(attrs.screen), &win_changes.width, &win_changes.height); win_changes.stack_mode = Above; DNOTE("Placing window at %d,%d with size %d,%d\n", win_changes.x, win_changes.y, win_changes.width, win_changes.height); XReconfigureWMWindow(dpy, win, 0, CWX | CWY | CWWidth | CWHeight | CWStackMode, &win_changes); //todo: check if these are correct and how to detect a kwm#if 0 /* Now try to set KWM hints */ WM_HINTS = XInternAtom(mydisplay, "KWM_WIN_DECORATION", True); if(WM_HINTS != None) { long KWMHints = 0; XChangeProperty(mydisplay, window.win, WM_HINTS, WM_HINTS, 32, PropModeReplace, (unsigned char *)&KWMHints, sizeof(KWMHints)/sizeof(long)); found_wm = 1; } /* Now try to unset KWM hints */ WM_HINTS = XInternAtom(mydisplay, "KWM_WIN_DECORATION", True); if(WM_HINTS != None) { XDeleteProperty(mydisplay, window.win, WM_HINTS); found_wm = 1; } #endif // If we have a gnome compliant wm that supports layers, put // us above the dock/panel if(gnome_wm_layers) { XEvent ev; ev.type = ClientMessage; ev.xclient.window = win; ev.xclient.message_type = XInternAtom(dpy, "_WIN_LAYER", True); ev.xclient.format = 32; ev.xclient.data.l[0] = 10; XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask, &ev); } else { if(wm_name != NULL) { if(strcmp(wm_name, "KWin") == 0) { XEvent ev; ev.type = ClientMessage; ev.xclient.window = win; ev.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", True); ev.xclient.format = 32; ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD ev.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_TOP", False); ev.xclient.data.l[2] = 0; XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask, &ev); } } } // Wait for a configure notify do { XNextEvent(dpy, &ev); } while(ev.type != ConfigureNotify); // save the configure event so we can return it ret_ev = ev; calc_coords(dpy, win, &x, &y, &ev); for(n = 0; n < 10; n++) { while(XCheckTypedEvent(dpy, ConfigureNotify, &ev) == True) { ret_ev = ev; calc_coords(dpy, win, &x, &y, &ev); } if(abs(x-win_changes.x) < 100 && abs(y-win_changes.y) < 100) { break; } usleep(100000); } //DNOTE("no more configure notify\n"); //try to move one more time, maybe we didn't get all configure events? if(x != win_changes.x || y != win_changes.y) { DNOTE("%s", "window is not at screen start. Trying to move again\n"); XSync(dpy, True); XReconfigureWMWindow(dpy, win, 0, CWX | CWY, &win_changes); /* do { XNextEvent(dpy, &ev); } while(ev.type != ConfigureNotify); ret_ev = ev; calc_coords(dpy, win, &x, &y, &ev); */ while(XCheckTypedEvent(dpy, ConfigureNotify, &ev) == True) { ret_ev = ev; calc_coords(dpy, win, &x, &y, &ev); } } // ugly hack, but what can you do when the wm's not removing decorations // if we don't end up at (win_changes.x, win_changes.y) // try to compensate and move one more time if((x != win_changes.x || y != win_changes.y) && abs(x - win_changes.x) < 100 && abs(y - win_changes.y) < 100) { XWindowChanges win_compensate; win_compensate.x = win_changes.x+win_changes.x-x; win_compensate.y = win_changes.y+win_changes.y-y; DNOTE("%s", "window is not at screen start\n"); DNOTE("Compensating by moving to x: %d= %d+%d-%d, y: %d= %d+%d-%d\n", win_compensate.x, win_changes.x, win_changes.x, x, win_compensate.y, win_changes.y, win_changes.y, y); XSync(dpy, True); XReconfigureWMWindow(dpy, win, 0, CWX | CWY, &win_compensate); do { XNextEvent(dpy, &ev); } while(ev.type != ConfigureNotify); ret_ev = ev; calc_coords(dpy, win, &x, &y, &ev); while(XCheckTypedEvent(dpy, ConfigureNotify, &ev) == True) { ret_ev = ev; calc_coords(dpy, win, &x, &y, &ev); } if(x != win_changes.x || y != win_changes.y) { DNOTE("Couldn't place window at %d,%d\n", win_changes.x, win_changes.y); DNOTE("Window is at %d, %d\n", x, y); } else { //DNOTE("Fixed, window is now at %d,%d\n", win_changes.x, win_changes.y); } } XPutBackEvent(dpy, &ret_ev); } else { // ewmh_state_fullscreen is supported XEvent ev; ev.type = ClientMessage; ev.xclient.window = win; ev.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", False); ev.xclient.format = 32; ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD not an atom just a define ev.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); ev.xclient.data.l[2] = 0; XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask, &ev); } current_state = WINDOW_STATE_FULLSCREEN; }static void switch_to_normal_state(Display *dpy, Window win){ XEvent ev; XSizeHints *sizehints; if(!has_ewmh_state_fullscreen) { // We don't want to have to replace the window manually when remapping it sizehints = XAllocSizeHints(); sizehints->flags = USPosition; sizehints->x = 0; // obsolete but should be set in case sizehints->y = 0; // an old wm is used // We have to be unmapped to change motif decoration hints withdraw_window(dpy, win); disable_motif_decorations(dpy, win); XSetWMNormalHints(dpy, win, sizehints); XFree(sizehints); XMapWindow(dpy, win); /* wait for the window to be mapped */ do { XNextEvent(dpy, &ev); } while(ev.type != MapNotify); /* remove any outstanding configure_notifies */ XSync(dpy, True); // get us back to the position and size we had before fullscreen restore_normal_geometry(dpy, win); // If we have a gnome compliant wm that supports layers, put // us in the normal layer if(gnome_wm_layers) { XEvent ev; ev.type = ClientMessage; ev.xclient.window = win; ev.xclient.message_type = XInternAtom(dpy, "_WIN_LAYER", True); ev.xclient.format = 32; ev.xclient.data.l[0] = 4; XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask, &ev); } else { if(wm_name != NULL) { if(strcmp(wm_name, "KWin") == 0) { XEvent ev; ev.type = ClientMessage; ev.xclient.window = win; ev.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", True); ev.xclient.format = 32; ev.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE ev.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_STAYS_ON_TOP", False); ev.xclient.data.l[2] = 0; XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask, &ev); } } } } else { // ewmh_state_fullscreen is supported XEvent ev; ev.type = ClientMessage; ev.xclient.window = win; ev.xclient.message_type = XInternAtom(dpy, "_NET_WM_STATE", False); ev.xclient.format = 32; ev.xclient.data.l[0] = 0; //_NET_WM_STATE_REMOVE not an atom just a define ev.xclient.data.l[1] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False); ev.xclient.data.l[2] = 0; XSendEvent(dpy, DefaultRootWindow(dpy), False, SubstructureNotifyMask, &ev); } current_state = WINDOW_STATE_NORMAL;}static int xprop_errorhandler(Display *dpy, XErrorEvent *ev){ if(ev->serial == req_serial) { /* this is an error to the XGetWindowProperty request * most probable the window specified by the property * _WIN_SUPPORTING_WM_CHECK on the root window no longer exists */ WARNING("%s", "xprop_errhandler: error in XGetWindowProperty\n"); return 0; } else { /* if we get another error we should handle it, * so we give it to the previous errorhandler */ ERROR("%s", "xprop_errhandler: unexpected error\n"); return prev_xerrhandler(dpy, ev); }}static int check_for_gnome_wm(Display *dpy){ Atom atom; Atom type_return; int format_return; unsigned long nitems_return; unsigned long bytes_after_return; unsigned char *prop_return = NULL; Window win_id; int status; atom = XInternAtom(dpy, "_WIN_SUPPORTING_WM_CHECK", True); if(atom == None) { return 0; } if(XGetWindowProperty(dpy, DefaultRootWindow(dpy), atom, 0, 1, False, XA_CARDINAL, &type_return, &format_return, &nitems_return, &bytes_after_return, &prop_return) != Success) { WARNING("%s", "XGetWindowProperty failed in check_for_gnome\n"); return 0; } if(type_return == None) { DNOTE("%s", "check_for_gnome: _WIN_SUPPORTING_WM_CHECK does not exist\n"); return 0; } if(type_return != XA_CARDINAL) { WARNING("%s", "check_for_gnome: _WIN_SUPPORTING_WM_CHECK has wrong type\n"); if(prop_return != NULL) { XFree(prop_return); } return 0; } if(type_return == XA_CARDINAL) { //DNOTE("check_for_gnome: format: %d\n", format_return); //DNOTE("check_for_gnome: nitmes: %ld\n", nitems_return); //DNOTE("check_for_gnome: bytes_after: %ld\n", bytes_after_return); if(format_return == 32 && nitems_return == 1 && bytes_after_return == 0) { win_id = *(long *)prop_return; //DNOTE("win_id: %ld\n", win_id); XFree(prop_return); prop_return = NULL; /* make sure we don't have any unhandled errors */ XSync(dpy, False); /* set error handler so we can check if XGetWindowProperty failed */ prev_xerrhandler = XSetErrorHandler(xprop_errorhandler); /* get the serial of the XGetWindowProperty request */ req_serial = NextRequest(dpy); /* try to get property * this can fail if we have a property with the win_id on the * root window, but the win_id is no longer valid. * example: we have had a gnome wm running but are now running * a non gnome wm. * question: shouldn't the gnome wm remove the property from * the root window when exiting ? bug in sawfish? */ status = XGetWindowProperty(dpy, win_id, atom, 0, 1, False, XA_CARDINAL, &type_return, &format_return, &nitems_return, &bytes_after_return, &prop_return); /* make sure XGetWindowProperty has been processed and any errors have been returned to us */ XSync(dpy, False); /* revert to the previous xerrorhandler */ XSetErrorHandler(prev_xerrhandler); if(status != Success) { WARNING("%s", "XGetWindowProperty failed in check_for_gnome\n"); return 0; } if(type_return == None) { DNOTE("%s", "check_for_gnome: _WIN_SUPPORTING_WM_CHECK does not exist in specified win\n"); return 0; } if(type_return != XA_CARDINAL) { WARNING("%s", "check_for_gnome: property has wrong type\n"); if(prop_return != NULL) { XFree(prop_return); } return 0; } if(type_return == XA_CARDINAL) { //DNOTE("check_for_gnome: format: %d\n", format_return); //DNOTE("check_for_gnome: nitmes: %ld\n", nitems_return); //DNOTE("check_for_gnome: bytes_after: %ld\n", bytes_after_return); if(format_return == 32 && nitems_return == 1 && bytes_after_return == 0) { //DNOTE("win_id: %ld\n", *(long *)prop_return); if(win_id == *(long *)prop_return) { // We have successfully detected a GNOME compliant Window Manager XFree(prop_return); return 1; } } XFree(prop_return); return 0; } } XFree(prop_return); return 0; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -