mirror of
				https://github.com/DreamMaoMao/maomaowm.git
				synced 2025-11-03 09:01:47 -05:00 
			
		
		
		
	feat: limit circle switch layout
This commit is contained in:
		
							parent
							
								
									d408c2fbd2
								
							
						
					
					
						commit
						de3af1e8c6
					
				
					 4 changed files with 184 additions and 18 deletions
				
			
		| 
						 | 
					@ -65,6 +65,10 @@ urgentcolor=0xad401fff
 | 
				
			||||||
scratchpadcolor=0x516c93ff
 | 
					scratchpadcolor=0x516c93ff
 | 
				
			||||||
globalcolor=0xb153a7ff
 | 
					globalcolor=0xb153a7ff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# layout circle limit
 | 
				
			||||||
 | 
					# if not set, it will circle all layout
 | 
				
			||||||
 | 
					# circle_layout=spiral,scroller
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# tags rule
 | 
					# tags rule
 | 
				
			||||||
# layout support: tile,scroller,grid,monocle,spiral,dwindle
 | 
					# layout support: tile,scroller,grid,monocle,spiral,dwindle
 | 
				
			||||||
tags=id:1,layout_name:tile
 | 
					tags=id:1,layout_name:tile
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										48
									
								
								maomao.c
									
										
									
									
									
								
							
							
						
						
									
										48
									
								
								maomao.c
									
										
									
									
									
								
							| 
						 | 
					@ -12,6 +12,7 @@
 | 
				
			||||||
#include <sys/wait.h>
 | 
					#include <sys/wait.h>
 | 
				
			||||||
#include <time.h>
 | 
					#include <time.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <wlr/types/wlr_fractional_scale_v1.h>
 | 
				
			||||||
#include <wayland-server-core.h>
 | 
					#include <wayland-server-core.h>
 | 
				
			||||||
#include <wlr/backend.h>
 | 
					#include <wlr/backend.h>
 | 
				
			||||||
#include <wlr/backend/libinput.h>
 | 
					#include <wlr/backend/libinput.h>
 | 
				
			||||||
| 
						 | 
					@ -4405,7 +4406,38 @@ setlayout(const Arg *arg) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void switch_layout(const Arg *arg) {
 | 
					void switch_layout(const Arg *arg) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int jk;
 | 
					  int jk,ji;
 | 
				
			||||||
 | 
					  char *target_layout_name=NULL;
 | 
				
			||||||
 | 
					  size_t len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if(config.circle_layout_count != 0) {
 | 
				
			||||||
 | 
					    for(jk = 0; jk < config.circle_layout_count; jk++) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      len = MAX(strlen(config.circle_layout[jk]), strlen(selmon->pertag->ltidxs[selmon->pertag->curtag]->name));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if(strncmp(config.circle_layout[jk], selmon->pertag->ltidxs[selmon->pertag->curtag]->name,len) == 0) {
 | 
				
			||||||
 | 
					        target_layout_name = jk == config.circle_layout_count - 1 ? config.circle_layout[0] : config.circle_layout[jk + 1];
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if(!target_layout_name) {
 | 
				
			||||||
 | 
					      target_layout_name = config.circle_layout[0];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (ji = 0; ji < LENGTH(layouts); ji++) {
 | 
				
			||||||
 | 
					      len = MAX(strlen(layouts[ji].name), strlen(target_layout_name));
 | 
				
			||||||
 | 
					      if (strncmp(layouts[ji].name,target_layout_name,len) == 0) {
 | 
				
			||||||
 | 
					        selmon->pertag->ltidxs[selmon->pertag->curtag] =  &layouts[ji];
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arrange(selmon, false);
 | 
				
			||||||
 | 
					    printstatus();
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (jk = 0; jk < LENGTH(layouts); jk++) {
 | 
					  for (jk = 0; jk < LENGTH(layouts); jk++) {
 | 
				
			||||||
    if (strcmp(layouts[jk].name,
 | 
					    if (strcmp(layouts[jk].name,
 | 
				
			||||||
               selmon->pertag->ltidxs[selmon->pertag->curtag]->name) == 0) {
 | 
					               selmon->pertag->ltidxs[selmon->pertag->curtag]->name) == 0) {
 | 
				
			||||||
| 
						 | 
					@ -5338,26 +5370,26 @@ void overview_restore(Client *c, const Arg *arg) {
 | 
				
			||||||
void switch_proportion_preset(const Arg *arg) {
 | 
					void switch_proportion_preset(const Arg *arg) {
 | 
				
			||||||
  float target_proportion = 0;
 | 
					  float target_proportion = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (LENGTH(scroller_proportion_preset) == 0) {
 | 
					  if (config.scroller_proportion_preset_count == 0) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (selmon->sel) {
 | 
					  if (selmon->sel) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (int i = 0; i < LENGTH(scroller_proportion_preset); i++) {
 | 
					    for (int i = 0; i < config.scroller_proportion_preset_count; i++) {
 | 
				
			||||||
      if (scroller_proportion_preset[i] == selmon->sel->scroller_proportion) {
 | 
					      if (config.scroller_proportion_preset[i] == selmon->sel->scroller_proportion) {
 | 
				
			||||||
        if (i == LENGTH(scroller_proportion_preset) - 1) {
 | 
					        if (i == config.scroller_proportion_preset_count - 1) {
 | 
				
			||||||
          target_proportion = scroller_proportion_preset[0];
 | 
					          target_proportion = config.scroller_proportion_preset[0];
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
          target_proportion = scroller_proportion_preset[i + 1];
 | 
					          target_proportion = config.scroller_proportion_preset[i + 1];
 | 
				
			||||||
          break;
 | 
					          break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (target_proportion == 0) {
 | 
					    if (target_proportion == 0) {
 | 
				
			||||||
      target_proportion = scroller_proportion_preset[0];
 | 
					      target_proportion = config.scroller_proportion_preset[0];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    unsigned int max_client_width =
 | 
					    unsigned int max_client_width =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										147
									
								
								parse_config.h
									
										
									
									
									
								
							
							
						
						
									
										147
									
								
								parse_config.h
									
										
									
									
									
								
							| 
						 | 
					@ -81,7 +81,11 @@ typedef struct {
 | 
				
			||||||
  int scroller_structs;
 | 
					  int scroller_structs;
 | 
				
			||||||
  float scroller_default_proportion;
 | 
					  float scroller_default_proportion;
 | 
				
			||||||
  int scoller_focus_center;
 | 
					  int scoller_focus_center;
 | 
				
			||||||
  float scroller_proportion_preset[3];
 | 
					  float *scroller_proportion_preset;
 | 
				
			||||||
 | 
					  int scroller_proportion_preset_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  char **circle_layout;
 | 
				
			||||||
 | 
					  int circle_layout_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  unsigned int new_is_master;
 | 
					  unsigned int new_is_master;
 | 
				
			||||||
  float default_mfact;
 | 
					  float default_mfact;
 | 
				
			||||||
| 
						 | 
					@ -154,6 +158,17 @@ typedef struct {
 | 
				
			||||||
typedef void (*FuncType)(const Arg *);
 | 
					typedef void (*FuncType)(const Arg *);
 | 
				
			||||||
Config config;
 | 
					Config config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// 清理字符串中的不可见字符(包括 \r, \n, 空格等)
 | 
				
			||||||
 | 
					char* sanitize_string(char *str) {
 | 
				
			||||||
 | 
					  // 去除首部不可见字符
 | 
				
			||||||
 | 
					  while (*str != '\0' && !isprint((unsigned char)*str)) str++;
 | 
				
			||||||
 | 
					  // 去除尾部不可见字符
 | 
				
			||||||
 | 
					  char *end = str + strlen(str) - 1;
 | 
				
			||||||
 | 
					  while (end > str && !isprint((unsigned char)*end)) end--;
 | 
				
			||||||
 | 
					  *(end + 1) = '\0';
 | 
				
			||||||
 | 
					  return str;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int parse_circle_direction(const char *str) {
 | 
					int parse_circle_direction(const char *str) {
 | 
				
			||||||
  // 将输入字符串转换为小写
 | 
					  // 将输入字符串转换为小写
 | 
				
			||||||
  char lowerStr[10];
 | 
					  char lowerStr[10];
 | 
				
			||||||
| 
						 | 
					@ -478,12 +493,108 @@ void parse_config_line(Config *config, const char *line) {
 | 
				
			||||||
  } else if (strcmp(key, "scoller_focus_center") == 0) {
 | 
					  } else if (strcmp(key, "scoller_focus_center") == 0) {
 | 
				
			||||||
    config->scoller_focus_center = atoi(value);
 | 
					    config->scoller_focus_center = atoi(value);
 | 
				
			||||||
  } else if (strcmp(key, "scroller_proportion_preset") == 0) {
 | 
					  } else if (strcmp(key, "scroller_proportion_preset") == 0) {
 | 
				
			||||||
    if (sscanf(value, "%f,%f,%f", &config->scroller_proportion_preset[0],
 | 
					    // 1. 统计 value 中有多少个逗号,确定需要解析的浮点数个数
 | 
				
			||||||
               &config->scroller_proportion_preset[1],
 | 
					    int count = 0; // 初始化为 0
 | 
				
			||||||
               &config->scroller_proportion_preset[2]) != 3) {
 | 
					    for (const char *p = value; *p; p++) {
 | 
				
			||||||
      fprintf(stderr, "Error: Invalid scroller_proportion_preset format: %s\n",
 | 
					        if (*p == ',') count++;
 | 
				
			||||||
              value);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    int float_count = count + 1; // 浮点数的数量是逗号数量加 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 2. 动态分配内存,存储浮点数
 | 
				
			||||||
 | 
					    config->scroller_proportion_preset = (float *)malloc(float_count * sizeof(float));
 | 
				
			||||||
 | 
					    if (!config->scroller_proportion_preset) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Error: Memory allocation failed\n");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 3. 解析 value 中的浮点数
 | 
				
			||||||
 | 
					    char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串
 | 
				
			||||||
 | 
					    char *token = strtok(value_copy, ",");
 | 
				
			||||||
 | 
					    int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (token != NULL && i < float_count) {
 | 
				
			||||||
 | 
					        if (sscanf(token, "%f", &config->scroller_proportion_preset[i]) != 1) {
 | 
				
			||||||
 | 
					            fprintf(stderr, "Error: Invalid float value in scroller_proportion_preset: %s\n", token);
 | 
				
			||||||
 | 
					            free(value_copy);
 | 
				
			||||||
 | 
					            free(config->scroller_proportion_preset); // 释放已分配的内存
 | 
				
			||||||
 | 
					            config->scroller_proportion_preset = NULL; // 防止野指针
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        token = strtok(NULL, ",");
 | 
				
			||||||
 | 
					        i++;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 4. 检查解析的浮点数数量是否匹配
 | 
				
			||||||
 | 
					    if (i != float_count) {
 | 
				
			||||||
 | 
					        fprintf(stderr, "Error: Invalid scroller_proportion_preset format: %s\n", value);
 | 
				
			||||||
 | 
					        free(value_copy);
 | 
				
			||||||
 | 
					        free(config->scroller_proportion_preset); // 释放已分配的内存
 | 
				
			||||||
 | 
					        config->scroller_proportion_preset = NULL; // 防止野指针
 | 
				
			||||||
 | 
					        config->scroller_proportion_preset_count = 0;
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    config->scroller_proportion_preset_count = float_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 5. 释放临时复制的字符串
 | 
				
			||||||
 | 
					    free(value_copy);
 | 
				
			||||||
 | 
					 } else if (strcmp(key, "circle_layout") == 0) {
 | 
				
			||||||
 | 
					  // 1. 统计 value 中有多少个逗号,确定需要解析的字符串个数
 | 
				
			||||||
 | 
					  int count = 0; // 初始化为 0
 | 
				
			||||||
 | 
					  for (const char *p = value; *p; p++) {
 | 
				
			||||||
 | 
					      if (*p == ',') count++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  int string_count = count + 1; // 字符串的数量是逗号数量加 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 2. 动态分配内存,存储字符串指针
 | 
				
			||||||
 | 
					  config->circle_layout = (char **)malloc(string_count * sizeof(char *));
 | 
				
			||||||
 | 
					  memset(config->circle_layout, 0, string_count * sizeof(char *));
 | 
				
			||||||
 | 
					  if (!config->circle_layout) {
 | 
				
			||||||
 | 
					      fprintf(stderr, "Error: Memory allocation failed\n");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 3. 解析 value 中的字符串
 | 
				
			||||||
 | 
					  char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串
 | 
				
			||||||
 | 
					  char *token = strtok(value_copy, ",");
 | 
				
			||||||
 | 
					  int i = 0;
 | 
				
			||||||
 | 
					  char *cleaned_token;
 | 
				
			||||||
 | 
					  while (token != NULL && i < string_count) {
 | 
				
			||||||
 | 
					      // 为每个字符串分配内存并复制内容
 | 
				
			||||||
 | 
					      cleaned_token = sanitize_string(token);
 | 
				
			||||||
 | 
					      config->circle_layout[i] = strdup(cleaned_token);
 | 
				
			||||||
 | 
					      if (!config->circle_layout[i]) {
 | 
				
			||||||
 | 
					          fprintf(stderr, "Error: Memory allocation failed for string: %s\n", token);
 | 
				
			||||||
 | 
					          // 释放之前分配的内存
 | 
				
			||||||
 | 
					          for (int j = 0; j < i; j++) {
 | 
				
			||||||
 | 
					              free(config->circle_layout[j]);
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          free(config->circle_layout);
 | 
				
			||||||
 | 
					          free(value_copy);
 | 
				
			||||||
 | 
					          config->circle_layout = NULL; // 防止野指针
 | 
				
			||||||
 | 
					          config->circle_layout_count = 0;
 | 
				
			||||||
 | 
					          return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      token = strtok(NULL, ",");
 | 
				
			||||||
 | 
					      i++;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 4. 检查解析的字符串数量是否匹配
 | 
				
			||||||
 | 
					  if (i != string_count) {
 | 
				
			||||||
 | 
					      fprintf(stderr, "Error: Invalid circle_layout format: %s\n", value);
 | 
				
			||||||
 | 
					      // 释放之前分配的内存
 | 
				
			||||||
 | 
					      for (int j = 0; j < i; j++) {
 | 
				
			||||||
 | 
					          free(config->circle_layout[j]);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      free(config->circle_layout);
 | 
				
			||||||
 | 
					      free(value_copy);
 | 
				
			||||||
 | 
					      config->circle_layout = NULL; // 防止野指针
 | 
				
			||||||
 | 
					      config->circle_layout_count = 0;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  config->circle_layout_count = string_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // 5. 释放临时复制的字符串
 | 
				
			||||||
 | 
					  free(value_copy);
 | 
				
			||||||
 } else if (strcmp(key, "new_is_master") == 0) {
 | 
					 } else if (strcmp(key, "new_is_master") == 0) {
 | 
				
			||||||
    config->new_is_master = atoi(value);
 | 
					    config->new_is_master = atoi(value);
 | 
				
			||||||
  } else if (strcmp(key, "default_mfact") == 0) {
 | 
					  } else if (strcmp(key, "default_mfact") == 0) {
 | 
				
			||||||
| 
						 | 
					@ -836,6 +947,22 @@ void parse_config_file(Config *config, const char *file_path) {
 | 
				
			||||||
  fclose(file);
 | 
					  fclose(file);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void free_circle_layout(Config *config) {
 | 
				
			||||||
 | 
					  if (config->circle_layout) {
 | 
				
			||||||
 | 
					      // 释放每个字符串
 | 
				
			||||||
 | 
					      for (int i = 0; i < config->circle_layout_count; i++) {
 | 
				
			||||||
 | 
					          if (config->circle_layout[i]) {
 | 
				
			||||||
 | 
					              free(config->circle_layout[i]); // 释放单个字符串
 | 
				
			||||||
 | 
					              config->circle_layout[i] = NULL; // 防止野指针
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      // 释放 circle_layout 数组本身
 | 
				
			||||||
 | 
					      free(config->circle_layout);
 | 
				
			||||||
 | 
					      config->circle_layout = NULL; // 防止野指针
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  config->circle_layout_count = 0; // 重置计数
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void free_config(void) {
 | 
					void free_config(void) {
 | 
				
			||||||
  // 释放内存
 | 
					  // 释放内存
 | 
				
			||||||
  int i;
 | 
					  int i;
 | 
				
			||||||
| 
						 | 
					@ -882,6 +1009,12 @@ void free_config(void) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  free(config.axis_bindings);
 | 
					  free(config.axis_bindings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  free(config.scroller_proportion_preset);
 | 
				
			||||||
 | 
					  config.scroller_proportion_preset = NULL;
 | 
				
			||||||
 | 
					  config.scroller_proportion_preset_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  free_circle_layout(&config);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void override_config(void) {
 | 
					void override_config(void) {
 | 
				
			||||||
| 
						 | 
					@ -898,8 +1031,6 @@ void override_config(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 复制数组类型的变量
 | 
					  // 复制数组类型的变量
 | 
				
			||||||
  memcpy(animation_curve, config.animation_curve, sizeof(animation_curve));
 | 
					  memcpy(animation_curve, config.animation_curve, sizeof(animation_curve));
 | 
				
			||||||
  memcpy(scroller_proportion_preset, config.scroller_proportion_preset,
 | 
					 | 
				
			||||||
         sizeof(scroller_proportion_preset));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  scroller_structs = config.scroller_structs;
 | 
					  scroller_structs = config.scroller_structs;
 | 
				
			||||||
  scroller_default_proportion = config.scroller_default_proportion;
 | 
					  scroller_default_proportion = config.scroller_default_proportion;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,6 @@ unsigned int gappov = 10; /* vert outer gap between windows and screen edge */
 | 
				
			||||||
int scroller_structs = 20;
 | 
					int scroller_structs = 20;
 | 
				
			||||||
float scroller_default_proportion = 0.9;
 | 
					float scroller_default_proportion = 0.9;
 | 
				
			||||||
int scoller_focus_center = 0;
 | 
					int scoller_focus_center = 0;
 | 
				
			||||||
float scroller_proportion_preset[] = {0.5, 0.9, 1.0};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int bypass_surface_visibility =
 | 
					int bypass_surface_visibility =
 | 
				
			||||||
    0; /* 1 means idle inhibitors will disable idle tracking even if it's
 | 
					    0; /* 1 means idle inhibitors will disable idle tracking even if it's
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue